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 = 68
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 uint32 // 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 [68]byte
67 copy(b[0:20], tx.FromEthAddr.Bytes())
68 pkComp := tx.FromBJJ.Compress()
69 copy(b[20:52], pkComp[:])
70 copy(b[52:56], tx.FromIdx.Bytes())
71 loadAmountFloat16, err := NewFloat16(tx.LoadAmount)
72 if err != nil {
73 return nil, err
74 }
75 copy(b[56:58], loadAmountFloat16.Bytes())
76 amountFloat16, err := NewFloat16(tx.Amount)
77 if err != nil {
78 return nil, err
79 }
80 copy(b[58:60], amountFloat16.Bytes())
81 copy(b[60:64], tx.TokenID.Bytes())
82 copy(b[64:68], tx.ToIdx.Bytes())
83 return b[:], nil
84}
85
86// L1TxFromBytes decodes a L1Tx from []byte
87func L1TxFromBytes(b []byte) (*L1Tx, error) {
88 if len(b) != L1TxBytesLen {
89 return nil, fmt.Errorf("Can not parse L1Tx bytes, expected length %d, current: %d", 68, len(b))
90 }
91
92 tx := &L1Tx{}
93 var err error
94 tx.FromEthAddr = ethCommon.BytesToAddress(b[0:20])
95 pkCompB := b[20:52]
96 var pkComp babyjub.PublicKeyComp
97 copy(pkComp[:], pkCompB)
98 tx.FromBJJ, err = pkComp.Decompress()
99 if err != nil {
100 return nil, err
101 }
102 tx.FromIdx, err = IdxFromBytes(b[52:56])
103 if err != nil {
104 return nil, err
105 }
106 tx.LoadAmount = Float16FromBytes(b[56:58]).BigInt()
107 tx.Amount = Float16FromBytes(b[58:60]).BigInt()
108 tx.TokenID, err = TokenIDFromBytes(b[60:64])
109 if err != nil {
110 return nil, err
111 }
112 tx.ToIdx, err = IdxFromBytes(b[64:68])
113 if err != nil {
114 return nil, err
115 }
116
117 return tx, nil
118}