hermez-node/common/l1tx.go
common/l1tx.goRaw
1package common
2
3import (
4 "fmt"
5 "math/big"
6
7 ethCommon "github.com/ethereum/go-ethereum/common"
8 "github.com/iden3/go-iden3-crypto/babyjub"
9)
10
11const (
12 // L1TxBytesLen is the length of the byte array that represents the L1Tx
13 L1TxBytesLen = 72
14)
15
16// L1Tx is a struct that represents a L1 tx
17type L1Tx struct {
18 // Stored in DB: mandatory fileds
19 TxID TxID
20 ToForgeL1TxsNum int64 // toForgeL1TxsNum in which the tx was forged / will be forged
21 Position int
22 UserOrigin bool // true if the tx was originated by a user, false if it was aoriginated by a coordinator. Note that this differ from the spec for implementation simplification purpposes
23 FromIdx Idx // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
24 FromEthAddr ethCommon.Address
25 FromBJJ *babyjub.PublicKey
26 ToIdx Idx // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
27 TokenID TokenID
28 Amount *big.Int
29 LoadAmount *big.Int
30 EthBlockNum int64 // Ethereum Block Number in which this L1Tx was added to the queue
31 Type TxType
32 BatchNum BatchNum
33}
34
35// Tx returns a *Tx from the L1Tx
36func (tx *L1Tx) Tx() *Tx {
37 f := new(big.Float).SetInt(tx.Amount)
38 amountFloat, _ := f.Float64()
39 genericTx := &Tx{
40 IsL1: true,
41 TxID: tx.TxID,
42 Type: tx.Type,
43 Position: tx.Position,
44 FromIdx: tx.FromIdx,
45 ToIdx: tx.ToIdx,
46 Amount: tx.Amount,
47 AmountFloat: amountFloat,
48 TokenID: tx.TokenID,
49 ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
50 UserOrigin: tx.UserOrigin,
51 FromEthAddr: tx.FromEthAddr,
52 FromBJJ: tx.FromBJJ,
53 LoadAmount: tx.LoadAmount,
54 EthBlockNum: tx.EthBlockNum,
55 }
56 if tx.LoadAmount != nil {
57 lf := new(big.Float).SetInt(tx.LoadAmount)
58 loadAmountFloat, _ := lf.Float64()
59 genericTx.LoadAmountFloat = loadAmountFloat
60 }
61 return genericTx
62}
63
64// Bytes encodes a L1Tx into []byte
65func (tx *L1Tx) Bytes(nLevels int) ([]byte, error) {
66 var b [L1TxBytesLen]byte
67 copy(b[0:20], tx.FromEthAddr.Bytes())
68 pkComp := tx.FromBJJ.Compress()
69 copy(b[20:52], pkComp[:])
70 fromIdxBytes, err := tx.FromIdx.Bytes()
71 if err != nil {
72 return nil, err
73 }
74 copy(b[52:58], fromIdxBytes[:])
75 loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
76 if err != nil {
77 return nil, err
78 }
79 copy(b[58:60], loadAmountFloat16.Bytes())
80 amountFloat16, err := NewFloat16(tx.Amount)
81 if err != nil {
82 return nil, err
83 }
84 copy(b[60:62], amountFloat16.Bytes())
85 copy(b[62:66], tx.TokenID.Bytes())
86 toIdxBytes, err := tx.ToIdx.Bytes()
87 if err != nil {
88 return nil, err
89 }
90 copy(b[66:72], toIdxBytes[:])
91 return b[:], nil
92}
93
94// L1TxFromBytes decodes a L1Tx from []byte
95func L1TxFromBytes(b []byte) (*L1Tx, error) {
96 if len(b) != L1TxBytesLen {
97 return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
98 }
99
100 tx := &L1Tx{}
101 var err error
102 tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
103 pkCompB := b[20:52]
104 var pkComp babyjub.PublicKeyComp
105 copy(pkComp[:], pkCompB)
106 tx.FromBJJ, err = pkComp.Decompress()
107 if err != nil {
108 return nil, err
109 }
110 tx.FromIdx, err = IdxFromBytes(b[52:58])
111 if err != nil {
112 return nil, err
113 }
114 tx.LoadAmount = Float16FromBytes(b[58:60]).BigInt()
115 tx.Amount = Float16FromBytes(b[60:62]).BigInt()
116 tx.TokenID, err = TokenIDFromBytes(b[62:66])
117 if err != nil {
118 return nil, err
119 }
120 tx.ToIdx, err = IdxFromBytes(b[66:72])
121 if err != nil {
122 return nil, err
123 }
124
125 return tx, nil
126}