hermez-node/test/txs.go
test/txs.goRaw
1package test
2
3import (
4 "crypto/ecdsa"
5 "math/big"
6 "strconv"
7 "testing"
8 "time"
9
10 ethCommon "github.com/ethereum/go-ethereum/common"
11 ethCrypto "github.com/ethereum/go-ethereum/crypto"
12 "github.com/hermeznetwork/hermez-node/common"
13 "github.com/iden3/go-iden3-crypto/babyjub"
14)
15
16type Account struct {
17 BJJ *babyjub.PrivateKey
18 Addr ethCommon.Address
19 Idx common.Idx
20 Nonce common.Nonce
21}
22
23// GenerateKeys generates BabyJubJub & Address keys for the given list of
24// account names in a deterministic way. This means, that for the same given
25// 'accNames' the keys will be always the same.
26func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
27 acc := make(map[string]*Account)
28 for i := 1; i < len(accNames)+1; i++ {
29 // babyjubjub key
30 var sk babyjub.PrivateKey
31 copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
32
33 // eth address
34 var key ecdsa.PrivateKey
35 key.D = big.NewInt(int64(i)) // only for testing
36 key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
37 key.Curve = ethCrypto.S256()
38 addr := ethCrypto.PubkeyToAddress(key.PublicKey)
39
40 a := Account{
41 BJJ: &sk,
42 Addr: addr,
43 Nonce: 0,
44 }
45 acc[accNames[i-1]] = &a
46 }
47 return acc
48}
49
50// GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
51// given Instructions.
52func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
53 accounts := GenerateKeys(t, instructions.Accounts)
54 l1CreatedAccounts := make(map[string]*Account)
55
56 var batchL1txs []*common.L1Tx
57 var batchCoordinatorL1txs []*common.L1Tx
58 var batchL2txs []*common.PoolL2Tx
59 var l1txs [][]*common.L1Tx
60 var coordinatorL1txs [][]*common.L1Tx
61 var l2txs [][]*common.PoolL2Tx
62 idx := 1
63 for _, inst := range instructions.Instructions {
64 switch inst.Type {
65 case common.TxTypeCreateAccountDeposit:
66 tx := common.L1Tx{
67 // TxID
68 FromEthAddr: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr,
69 FromBJJ: accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(),
70 TokenID: inst.TokenID,
71 LoadAmount: big.NewInt(int64(inst.Amount)),
72 Type: common.TxTypeCreateAccountDeposit,
73 }
74 batchL1txs = append(batchL1txs, &tx)
75 if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx
76 accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx)
77
78 l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)]
79 idx++
80 }
81 case common.TxTypeTransfer:
82 // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
83 if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok {
84 tx := common.L1Tx{
85 FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
86 FromBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
87 TokenID: inst.TokenID,
88 LoadAmount: big.NewInt(int64(inst.Amount)),
89 Type: common.TxTypeCreateAccountDeposit,
90 }
91 accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx)
92 l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)]
93 batchCoordinatorL1txs = append(batchCoordinatorL1txs, &tx)
94 idx++
95 }
96
97 tx := common.PoolL2Tx{
98 // TxID: nil,
99 FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
100 ToIdx: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx,
101 ToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
102 ToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
103 TokenID: inst.TokenID,
104 Amount: big.NewInt(int64(inst.Amount)),
105 Fee: common.FeeSelector(inst.Fee),
106 Nonce: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce,
107 State: common.PoolL2TxStatePending,
108 Timestamp: time.Now(),
109 BatchNum: 0,
110 RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
111 RqToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
112 Type: common.TxTypeTransfer,
113 }
114 // perform signature and set it to tx.Signature
115 toSign, err := tx.HashToSign()
116 if err != nil {
117 panic(err)
118 }
119 sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
120 tx.Signature = sig
121
122 accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
123 batchL2txs = append(batchL2txs, &tx)
124
125 case common.TxTypeExit, common.TxTypeForceExit:
126 tx := common.L1Tx{
127 FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
128 ToIdx: common.Idx(1), // as is an Exit
129 TokenID: inst.TokenID,
130 Amount: big.NewInt(int64(inst.Amount)),
131 Type: common.TxTypeExit,
132 }
133 batchL1txs = append(batchL1txs, &tx)
134 case TypeNewBatch:
135 l1txs = append(l1txs, batchL1txs)
136 coordinatorL1txs = append(coordinatorL1txs, batchCoordinatorL1txs)
137 l2txs = append(l2txs, batchL2txs)
138 batchL1txs = []*common.L1Tx{}
139 batchCoordinatorL1txs = []*common.L1Tx{}
140 batchL2txs = []*common.PoolL2Tx{}
141 default:
142 continue
143 }
144
145 }
146 l1txs = append(l1txs, batchL1txs)
147 coordinatorL1txs = append(coordinatorL1txs, batchCoordinatorL1txs)
148 l2txs = append(l2txs, batchL2txs)
149
150 return l1txs, coordinatorL1txs, l2txs
151}