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 USD *float64
34 LoadAmountUSD *float64
35}
36
37// Tx returns a *Tx from the L1Tx
38func (tx *L1Tx) Tx() *Tx {
39 f := new(big.Float).SetInt(tx.Amount)
40 amountFloat, _ := f.Float64()
41 genericTx := &Tx{
42 IsL1: true,
43 TxID: tx.TxID,
44 Type: tx.Type,
45 Position: tx.Position,
46 FromIdx: tx.FromIdx,
47 ToIdx: tx.ToIdx,
48 Amount: tx.Amount,
49 AmountFloat: amountFloat,
50 TokenID: tx.TokenID,
51 ToForgeL1TxsNum: tx.ToForgeL1TxsNum,
52 UserOrigin: tx.UserOrigin,
53 FromEthAddr: tx.FromEthAddr,
54 FromBJJ: tx.FromBJJ,
55 LoadAmount: tx.LoadAmount,
56 EthBlockNum: tx.EthBlockNum,
57 USD: tx.USD,
58 LoadAmountUSD: tx.LoadAmountUSD,
59 }
60 if tx.LoadAmount != nil {
61 lf := new(big.Float).SetInt(tx.LoadAmount)
62 loadAmountFloat, _ := lf.Float64()
63 genericTx.LoadAmountFloat = &loadAmountFloat
64 }
65 return genericTx
66}
67
68// Bytes encodes a L1Tx into []byte
69func (tx *L1Tx) Bytes(nLevels int) ([]byte, error) {
70 var b [L1TxBytesLen]byte
71 copy(b[0:20], tx.FromEthAddr.Bytes())
72 pkComp := tx.FromBJJ.Compress()
73 copy(b[20:52], pkComp[:])
74 fromIdxBytes, err := tx.FromIdx.Bytes()
75 if err != nil {
76 return nil, err
77 }
78 copy(b[52:58], fromIdxBytes[:])
79 loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
80 if err != nil {
81 return nil, err
82 }
83 copy(b[58:60], loadAmountFloat16.Bytes())
84 amountFloat16, err := NewFloat16(tx.Amount)
85 if err != nil {
86 return nil, err
87 }
88 copy(b[60:62], amountFloat16.Bytes())
89 copy(b[62:66], tx.TokenID.Bytes())
90 toIdxBytes, err := tx.ToIdx.Bytes()
91 if err != nil {
92 return nil, err
93 }
94 copy(b[66:72], toIdxBytes[:])
95 return b[:], nil
96}
97
98// L1TxFromBytes decodes a L1Tx from []byte
99func L1TxFromBytes(b []byte) (*L1Tx, error) {
100 if len(b) != L1TxBytesLen {
101 return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
102 }
103
104 tx := &L1Tx{}
105 var err error
106 tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
107 pkCompB := b[20:52]
108 var pkComp babyjub.PublicKeyComp
109 copy(pkComp[:], pkCompB)
110 tx.FromBJJ, err = pkComp.Decompress()
111 if err != nil {
112 return nil, err
113 }
114 tx.FromIdx, err = IdxFromBytes(b[52:58])
115 if err != nil {
116 return nil, err
117 }
118 tx.LoadAmount = Float16FromBytes(b[58:60]).BigInt()
119 tx.Amount = Float16FromBytes(b[60:62]).BigInt()
120 tx.TokenID, err = TokenIDFromBytes(b[62:66])
121 if err != nil {
122 return nil, err
123 }
124 tx.ToIdx, err = IdxFromBytes(b[66:72])
125 if err != nil {
126 return nil, err
127 }
128
129 return tx, nil
130}