hermez-node/common/pooll2tx.go
common/pooll2tx.goRaw
1package common
2
3import (
4 "encoding/binary"
5 "fmt"
6 "math/big"
7 "time"
8
9 eth "github.com/ethereum/go-ethereum/common"
10 "github.com/hermeznetwork/hermez-node/utils"
11 "github.com/iden3/go-iden3-crypto/babyjub"
12)
13
14// Nonce represents the nonce value in a uint64, which has the method Bytes that returns a byte array of length 5 (40 bits).
15type Nonce uint64
16
17// Bytes returns a byte array of length 5 representing the Nonce
18func (n Nonce) Bytes() ([5]byte, error) {
19 if n >= 1099511627776 { // 2**40bits
20 return [5]byte{}, ErrNonceOverflow
21 }
22 var nonceBytes [8]byte
23 binary.LittleEndian.PutUint64(nonceBytes[:], uint64(n))
24 var b [5]byte
25 copy(b[:], nonceBytes[:5])
26 return b, nil
27}
28
29func NonceFromBytes(b [5]byte) (Nonce, error) {
30 var nonceBytes [8]byte
31 copy(nonceBytes[:], b[:5])
32 nonce := binary.LittleEndian.Uint64(nonceBytes[:])
33 return Nonce(nonce), nil
34}
35
36// PoolL2Tx is a struct that represents a L2Tx sent by an account to the coordinator hat is waiting to be forged
37type PoolL2Tx struct {
38 // Stored in DB: mandatory fileds
39 TxID TxID `meddler:"tx_id"`
40 FromIdx Idx `meddler:"from_idx"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
41 ToIdx Idx `meddler:"to_idx"` // ToIdx is ignored in L1Tx/Deposit, but used in the L1Tx/DepositAndTransfer
42 ToEthAddr eth.Address `meddler:"to_eth_addr"`
43 ToBJJ *babyjub.PublicKey `meddler:"to_bjj"` // TODO: stop using json, use scanner/valuer
44 TokenID TokenID `meddler:"token_id"`
45 Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16
46 Fee FeeSelector `meddler:"fee"`
47 Nonce Nonce `meddler:"nonce"` // effective 40 bits used
48 State PoolL2TxState `meddler:"state"`
49 Signature babyjub.Signature `meddler:"signature"` // tx signature
50 Timestamp time.Time `meddler:"timestamp,utctime"` // time when added to the tx pool
51 // Stored in DB: optional fileds, may be uninitialized
52 BatchNum BatchNum `meddler:"batch_num,zeroisnull"` // batchNum in which this tx was forged. Presence indicates "forged" state.
53 RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
54 RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit)
55 RqToEthAddr eth.Address `meddler:"rq_to_eth_addr"`
56 RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"` // TODO: stop using json, use scanner/valuer
57 RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
58 RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16
59 RqFee FeeSelector `meddler:"rq_fee,zeroisnull"`
60 RqNonce uint64 `meddler:"rq_nonce,zeroisnull"` // effective 48 bits used
61 AbsoluteFee float64 `meddler:"absolute_fee,zeroisnull"`
62 AbsoluteFeeUpdate time.Time `meddler:"absolute_fee_update,utctimez"`
63 // Extra metadata, may be uninitialized
64 Type TxType `meddler:"-"` // optional, descrives which kind of tx it's
65 RqTxCompressedData []byte `meddler:"-"` // 253 bits, optional for atomic txs
66}
67
68// TxCompressedData spec:
69// [ 32 bits ] signatureConstant // 4 bytes: [0:4]
70// [ 16 bits ] chainId // 2 bytes: [4:6]
71// [ 48 bits ] fromIdx // 6 bytes: [6:12]
72// [ 48 bits ] toIdx // 6 bytes: [12:18]
73// [ 16 bits ] amountFloat16 // 2 bytes: [18:20]
74// [ 32 bits ] tokenID // 4 bytes: [20:24]
75// [ 40 bits ] nonce // 5 bytes: [24:29]
76// [ 8 bits ] userFee // 1 byte: [29:30]
77// [ 1 bits ] toBjjSign // 1 byte: [30:31]
78// Total bits compressed data: 241 bits // 31 bytes in *big.Int representation
79func (tx *PoolL2Tx) TxCompressedData() (*big.Int, error) {
80 // sigconstant
81 sc, ok := new(big.Int).SetString("3322668559", 10)
82 if !ok {
83 return nil, fmt.Errorf("error parsing SignatureConstant")
84 }
85
86 amountFloat16, err := utils.NewFloat16(tx.Amount)
87 if err != nil {
88 return nil, err
89 }
90 var b [31]byte
91 copy(b[:4], SwapEndianness(sc.Bytes()))
92 copy(b[4:6], []byte{1, 0, 0, 0}) // LittleEndian representation of uint32(1) for Ethereum
93 copy(b[6:12], tx.FromIdx.Bytes())
94 copy(b[12:18], tx.ToIdx.Bytes())
95 copy(b[18:20], amountFloat16.Bytes())
96 copy(b[20:24], tx.TokenID.Bytes())
97 nonceBytes, err := tx.Nonce.Bytes()
98 if err != nil {
99 return nil, err
100 }
101 copy(b[24:29], nonceBytes[:])
102 b[29] = byte(tx.Fee)
103 toBjjSign := byte(0)
104 if babyjub.PointCoordSign(tx.ToBJJ.X) {
105 toBjjSign = byte(1)
106 }
107 b[30] = toBjjSign
108 bi := new(big.Int).SetBytes(SwapEndianness(b[:]))
109
110 return bi, nil
111}
112
113// TxCompressedDataV2 spec:
114// [ 48 bits ] fromIdx // 6 bytes: [0:6]
115// [ 48 bits ] toIdx // 6 bytes: [6:12]
116// [ 16 bits ] amountFloat16 // 2 bytes: [12:14]
117// [ 32 bits ] tokenID // 4 bytes: [14:18]
118// [ 40 bits ] nonce // 5 bytes: [18:23]
119// [ 8 bits ] userFee // 1 byte: [23:24]
120// [ 1 bits ] toBjjSign // 1 byte: [24:25]
121// Total bits compressed data: 193 bits // 25 bytes in *big.Int representation
122func (tx *PoolL2Tx) TxCompressedDataV2() (*big.Int, error) {
123 amountFloat16, err := utils.NewFloat16(tx.Amount)
124 if err != nil {
125 return nil, err
126 }
127 var b [25]byte
128 copy(b[0:6], tx.FromIdx.Bytes())
129 copy(b[6:12], tx.ToIdx.Bytes())
130 copy(b[12:14], amountFloat16.Bytes())
131 copy(b[14:18], tx.TokenID.Bytes())
132 nonceBytes, err := tx.Nonce.Bytes()
133 if err != nil {
134 return nil, err
135 }
136 copy(b[18:23], nonceBytes[:])
137 b[23] = byte(tx.Fee)
138 toBjjSign := byte(0)
139 if babyjub.PointCoordSign(tx.ToBJJ.X) {
140 toBjjSign = byte(1)
141 }
142 b[24] = toBjjSign
143
144 bi := new(big.Int).SetBytes(SwapEndianness(b[:]))
145 return bi, nil
146}
147
148func (tx *PoolL2Tx) Tx() *Tx {
149 return &Tx{
150 TxID: tx.TxID,
151 FromIdx: tx.FromIdx,
152 ToIdx: tx.ToIdx,
153 TokenID: tx.TokenID,
154 Amount: tx.Amount,
155 Nonce: tx.Nonce,
156 Fee: tx.Fee,
157 Type: tx.Type,
158 }
159}
160
161// PoolL2TxState is a struct that represents the status of a L2 transaction
162type PoolL2TxState string
163
164const (
165 // PoolL2TxStatePending represents a valid L2Tx that hasn't started the forging process
166 PoolL2TxStatePending PoolL2TxState = "pend"
167 // PoolL2TxStateForging represents a valid L2Tx that has started the forging process
168 PoolL2TxStateForging PoolL2TxState = "fing"
169 // PoolL2TxStateForged represents a L2Tx that has already been forged
170 PoolL2TxStateForged PoolL2TxState = "fged"
171 // PoolL2TxStateInvalid represents a L2Tx that has been invalidated
172 PoolL2TxStateInvalid PoolL2TxState = "invl"
173)