hermez-node/common/l2tx.go
common/l2tx.goRaw
1package common
2
3import (
4 "fmt"
5 "math/big"
6
7 "github.com/hermeznetwork/tracerr"
8)
9
10// L2Tx is a struct that represents an already forged L2 tx
11type L2Tx struct {
12 // Stored in DB: mandatory fileds
13 TxID TxID `meddler:"id"`
14 BatchNum BatchNum `meddler:"batch_num"` // batchNum in which this tx was forged.
15 Position int `meddler:"position"`
16 FromIdx Idx `meddler:"from_idx"`
17 ToIdx Idx `meddler:"to_idx"`
18 Amount *big.Int `meddler:"amount,bigint"`
19 Fee FeeSelector `meddler:"fee"`
20 Nonce Nonce `meddler:"nonce"`
21 Type TxType `meddler:"type"`
22 EthBlockNum int64 `meddler:"eth_block_num"` // Ethereum Block Number in which this L2Tx was added to the queue
23}
24
25// NewL2Tx returns the given L2Tx with the TxId & Type parameters calculated
26// from the L2Tx values
27func NewL2Tx(l2Tx *L2Tx) (*L2Tx, error) {
28 // calculate TxType
29 var txType TxType
30 if l2Tx.ToIdx == Idx(1) {
31 txType = TxTypeExit
32 } else if l2Tx.ToIdx >= IdxUserThreshold {
33 txType = TxTypeTransfer
34 } else {
35 return l2Tx, tracerr.Wrap(fmt.Errorf("Can not determine type of L2Tx, invalid ToIdx value: %d", l2Tx.ToIdx))
36 }
37
38 // if TxType!=l2Tx.TxType return error
39 if l2Tx.Type != "" && l2Tx.Type != txType {
40 return l2Tx, tracerr.Wrap(fmt.Errorf("L2Tx.Type: %s, should be: %s", l2Tx.Type, txType))
41 }
42 l2Tx.Type = txType
43
44 var txid [TxIDLen]byte
45 txid[0] = TxIDPrefixL2Tx
46 fromIdxBytes, err := l2Tx.FromIdx.Bytes()
47 if err != nil {
48 return l2Tx, tracerr.Wrap(err)
49 }
50 copy(txid[1:7], fromIdxBytes[:])
51 nonceBytes, err := l2Tx.Nonce.Bytes()
52 if err != nil {
53 return l2Tx, tracerr.Wrap(err)
54 }
55 copy(txid[7:12], nonceBytes[:])
56 l2Tx.TxID = TxID(txid)
57
58 return l2Tx, nil
59}
60
61// Tx returns a *Tx from the L2Tx
62func (tx *L2Tx) Tx() *Tx {
63 batchNum := new(BatchNum)
64 *batchNum = tx.BatchNum
65 fee := new(FeeSelector)
66 *fee = tx.Fee
67 nonce := new(Nonce)
68 *nonce = tx.Nonce
69 return &Tx{
70 IsL1: false,
71 TxID: tx.TxID,
72 Type: tx.Type,
73 Position: tx.Position,
74 FromIdx: tx.FromIdx,
75 ToIdx: tx.ToIdx,
76 Amount: tx.Amount,
77 BatchNum: batchNum,
78 EthBlockNum: tx.EthBlockNum,
79 Fee: fee,
80 Nonce: nonce,
81 }
82}
83
84// PoolL2Tx returns the data structure of PoolL2Tx with the parameters of a
85// L2Tx filled
86func (tx L2Tx) PoolL2Tx() *PoolL2Tx {
87 return &PoolL2Tx{
88 TxID: tx.TxID,
89 FromIdx: tx.FromIdx,
90 ToIdx: tx.ToIdx,
91 Amount: tx.Amount,
92 Fee: tx.Fee,
93 Nonce: tx.Nonce,
94 Type: tx.Type,
95 }
96}
97
98// L2TxsToPoolL2Txs returns an array of []*PoolL2Tx from an array of []*L2Tx,
99// where the PoolL2Tx only have the parameters of a L2Tx filled.
100func L2TxsToPoolL2Txs(txs []L2Tx) []PoolL2Tx {
101 var r []PoolL2Tx
102 for _, tx := range txs {
103 r = append(r, *tx.PoolL2Tx())
104 }
105 return r
106}
107
108// BytesDataAvailability encodes a L2Tx into []byte for the Data Availability
109func (tx L2Tx) BytesDataAvailability(nLevels uint32) ([]byte, error) {
110 idxLen := nLevels / 8 //nolint:gomnd
111
112 b := make([]byte, ((nLevels*2)+16+8)/8) //nolint:gomnd
113
114 fromIdxBytes, err := tx.FromIdx.Bytes()
115 if err != nil {
116 return nil, tracerr.Wrap(err)
117 }
118 copy(b[0:idxLen], fromIdxBytes[6-idxLen:]) // [6-idxLen:] as is BigEndian
119
120 toIdxBytes, err := tx.ToIdx.Bytes()
121 if err != nil {
122 return nil, tracerr.Wrap(err)
123 }
124 copy(b[idxLen:idxLen*2], toIdxBytes[6-idxLen:])
125
126 amountFloat16, err := NewFloat16(tx.Amount)
127 if err != nil {
128 return nil, tracerr.Wrap(err)
129 }
130
131 copy(b[idxLen*2:idxLen*2+2], amountFloat16.Bytes())
132 b[idxLen*2+2] = byte(tx.Fee)
133
134 return b[:], nil
135}
136
137// L2TxFromBytesDataAvailability decodes a L2Tx from []byte (Data Availability)
138func L2TxFromBytesDataAvailability(b []byte, nLevels int) (*L2Tx, error) {
139 idxLen := nLevels / 8 //nolint:gomnd
140 tx := &L2Tx{}
141 var err error
142
143 var paddedFromIdxBytes [6]byte
144 copy(paddedFromIdxBytes[6-idxLen:], b[0:idxLen])
145 tx.FromIdx, err = IdxFromBytes(paddedFromIdxBytes[:])
146 if err != nil {
147 return nil, tracerr.Wrap(err)
148 }
149
150 var paddedToIdxBytes [6]byte
151 copy(paddedToIdxBytes[6-idxLen:6], b[idxLen:idxLen*2])
152 tx.ToIdx, err = IdxFromBytes(paddedToIdxBytes[:])
153 if err != nil {
154 return nil, tracerr.Wrap(err)
155 }
156
157 tx.Amount = Float16FromBytes(b[idxLen*2 : idxLen*2+2]).BigInt()
158 tx.Fee = FeeSelector(b[idxLen*2+2])
159 return tx, nil
160}