hermez-node/test/ethclient_test.go
test/ethclient_test.goRaw
1package test
2
3import (
4 "context"
5 "crypto/ecdsa"
6 "encoding/binary"
7 "math/big"
8 "testing"
9 "time"
10
11 ethCommon "github.com/ethereum/go-ethereum/common"
12 ethCrypto "github.com/ethereum/go-ethereum/crypto"
13 "github.com/hermeznetwork/hermez-node/common"
14 "github.com/hermeznetwork/hermez-node/eth"
15 "github.com/iden3/go-iden3-crypto/babyjub"
16 "github.com/stretchr/testify/assert"
17 "github.com/stretchr/testify/require"
18)
19
20type timer struct {
21 time int64
22}
23
24func (t *timer) Time() int64 {
25 currentTime := t.time
26 t.time++
27 return currentTime
28}
29
30func TestClientInterface(t *testing.T) {
31 var c eth.ClientInterface
32 var timer timer
33 clientSetup := NewClientSetupExample()
34 client := NewClient(true, &timer, ðCommon.Address{}, clientSetup)
35 c = client
36 require.NotNil(t, c)
37}
38
39func TestClientEth(t *testing.T) {
40 var timer timer
41 clientSetup := NewClientSetupExample()
42 c := NewClient(true, &timer, ðCommon.Address{}, clientSetup)
43 blockNum, err := c.EthCurrentBlock()
44 require.Nil(t, err)
45 assert.Equal(t, int64(1), blockNum)
46
47 block, err := c.EthBlockByNumber(context.TODO(), 0)
48 require.Nil(t, err)
49 assert.Equal(t, int64(0), block.EthBlockNum)
50 assert.Equal(t, time.Unix(0, 0), block.Timestamp)
51 assert.Equal(t, "0x0000000000000000000000000000000000000000000000000000000000000000", block.Hash.Hex())
52
53 // Mine some empty blocks
54
55 assert.Equal(t, int64(1), c.blockNum)
56 c.CtlMineBlock()
57 assert.Equal(t, int64(2), c.blockNum)
58 c.CtlMineBlock()
59 assert.Equal(t, int64(3), c.blockNum)
60
61 block, err = c.EthBlockByNumber(context.TODO(), 2)
62 require.Nil(t, err)
63 assert.Equal(t, int64(2), block.EthBlockNum)
64 assert.Equal(t, time.Unix(2, 0), block.Timestamp)
65
66 // Add a token
67 tokenAddr := ethCommon.HexToAddress("0x44021007485550008e0f9f1f7b506c7d970ad8ce")
68 constants := eth.ERC20Consts{
69 Name: "FooBar",
70 Symbol: "FOO",
71 Decimals: 4,
72 }
73 c.CtlAddERC20(tokenAddr, constants)
74 c.CtlMineBlock()
75 tokenConstants, err := c.EthERC20Consts(tokenAddr)
76 require.Nil(t, err)
77 assert.Equal(t, constants, *tokenConstants)
78}
79
80func TestClientAuction(t *testing.T) {
81 addrBidder1 := ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
82 addrBidder2 := ethCommon.HexToAddress("0xc27cadc437d067a6ec869502cc9f7F834cFc087a")
83 addrForge := ethCommon.HexToAddress("0xCfAA413eEb796f328620a3630Ae39124cabcEa92")
84 addrForge2 := ethCommon.HexToAddress("0x1fCb4ac309428feCc61B1C8cA5823C15A5e1a800")
85
86 var timer timer
87 clientSetup := NewClientSetupExample()
88 clientSetup.AuctionVariables.ClosedAuctionSlots = 2
89 clientSetup.AuctionVariables.OpenAuctionSlots = 4320
90 clientSetup.AuctionVariables.DefaultSlotSetBid = [6]*big.Int{
91 big.NewInt(1000), big.NewInt(1100), big.NewInt(1200),
92 big.NewInt(1300), big.NewInt(1400), big.NewInt(1500)}
93 c := NewClient(true, &timer, &addrBidder1, clientSetup)
94
95 // Check several cases in which bid doesn't succed, and also do 2 successful bids.
96
97 _, err := c.AuctionBidSimple(0, big.NewInt(1))
98 assert.Equal(t, errBidClosed, err)
99
100 _, err = c.AuctionBidSimple(4322, big.NewInt(1))
101 assert.Equal(t, errBidNotOpen, err)
102
103 // 101 % 6 = 5; defaultSlotSetBid[5] = 1500; 1500 + 10% = 1650
104 _, err = c.AuctionBidSimple(101, big.NewInt(1650))
105 assert.Equal(t, errCoordNotReg, err)
106
107 _, err = c.AuctionSetCoordinator(addrForge, "https://foo.bar")
108 assert.Nil(t, err)
109
110 _, err = c.AuctionBidSimple(3, big.NewInt(1))
111 assert.Equal(t, errBidBelowMin, err)
112
113 _, err = c.AuctionBidSimple(3, big.NewInt(1650))
114 assert.Nil(t, err)
115
116 c.CtlSetAddr(addrBidder2)
117 _, err = c.AuctionSetCoordinator(addrForge2, "https://foo2.bar")
118 assert.Nil(t, err)
119
120 _, err = c.AuctionBidSimple(3, big.NewInt(16))
121 assert.Equal(t, errBidBelowMin, err)
122
123 // 1650 + 10% = 1815
124 _, err = c.AuctionBidSimple(3, big.NewInt(1815))
125 assert.Nil(t, err)
126
127 c.CtlMineBlock()
128
129 blockNum, err := c.EthCurrentBlock()
130 require.Nil(t, err)
131
132 auctionEvents, _, err := c.AuctionEventsByBlock(blockNum)
133 require.Nil(t, err)
134 assert.Equal(t, 2, len(auctionEvents.NewBid))
135}
136
137func TestClientRollup(t *testing.T) {
138 token1Addr := ethCommon.HexToAddress("0x6b175474e89094c44da98b954eedeac495271d0f")
139
140 var timer timer
141 clientSetup := NewClientSetupExample()
142 c := NewClient(true, &timer, ðCommon.Address{}, clientSetup)
143
144 // Add a token
145
146 tx, err := c.RollupAddTokenSimple(token1Addr, clientSetup.RollupVariables.FeeAddToken)
147 require.Nil(t, err)
148 assert.NotNil(t, tx)
149
150 // Add some L1UserTxs
151 // Create Accounts
152
153 const N = 16
154 var keys [N]*keys
155 for i := 0; i < N; i++ {
156 keys[i] = genKeys(int64(i))
157 tx := common.L1Tx{
158 FromIdx: 0,
159 FromEthAddr: keys[i].Addr,
160 FromBJJ: keys[i].BJJPublicKey,
161 TokenID: common.TokenID(0),
162 Amount: big.NewInt(0),
163 LoadAmount: big.NewInt(10 + int64(i)),
164 }
165 _, err := c.RollupL1UserTxERC20ETH(tx.FromBJJ, int64(tx.FromIdx), tx.LoadAmount,
166 tx.Amount, uint32(tx.TokenID), int64(tx.ToIdx))
167 require.Nil(t, err)
168 }
169 c.CtlMineBlock()
170
171 blockNum, err := c.EthCurrentBlock()
172 require.Nil(t, err)
173 rollupEvents, _, err := c.RollupEventsByBlock(blockNum)
174 require.Nil(t, err)
175 assert.Equal(t, N, len(rollupEvents.L1UserTx))
176 assert.Equal(t, 1, len(rollupEvents.AddToken))
177
178 // Forge a batch
179
180 c.CtlAddBatch(ð.RollupForgeBatchArgs{
181 NewLastIdx: 0,
182 NewStRoot: big.NewInt(1),
183 NewExitRoot: big.NewInt(100),
184 L1CoordinatorTxs: []common.L1Tx{},
185 L2TxsData: []common.L2Tx{},
186 FeeIdxCoordinator: []common.Idx{},
187 VerifierIdx: 0,
188 L1Batch: true,
189 })
190 c.CtlMineBlock()
191
192 blockNumA, err := c.EthCurrentBlock()
193 require.Nil(t, err)
194 rollupEvents, hashA, err := c.RollupEventsByBlock(blockNumA)
195 require.Nil(t, err)
196 assert.Equal(t, 0, len(rollupEvents.L1UserTx))
197 assert.Equal(t, 0, len(rollupEvents.AddToken))
198 assert.Equal(t, 1, len(rollupEvents.ForgeBatch))
199
200 // Simulate reorg discarding last mined block
201
202 c.CtlRollback()
203 c.CtlMineBlock()
204
205 blockNumB, err := c.EthCurrentBlock()
206 require.Nil(t, err)
207 rollupEvents, hashB, err := c.RollupEventsByBlock(blockNumA)
208 require.Nil(t, err)
209 assert.Equal(t, 0, len(rollupEvents.L1UserTx))
210 assert.Equal(t, 0, len(rollupEvents.AddToken))
211 assert.Equal(t, 0, len(rollupEvents.ForgeBatch))
212
213 assert.Equal(t, blockNumA, blockNumB)
214 assert.NotEqual(t, hashA, hashB)
215
216 // Forge again
217 rollupForgeBatchArgs0 := ð.RollupForgeBatchArgs{
218 NewLastIdx: 0,
219 NewStRoot: big.NewInt(1),
220 NewExitRoot: big.NewInt(100),
221 L1CoordinatorTxs: []common.L1Tx{},
222 L2TxsData: []common.L2Tx{},
223 FeeIdxCoordinator: []common.Idx{},
224 VerifierIdx: 0,
225 L1Batch: true,
226 }
227 c.CtlAddBatch(rollupForgeBatchArgs0)
228 c.CtlMineBlock()
229
230 // Retrieve ForgeBatchArguments starting from the events
231
232 blockNum, err = c.EthCurrentBlock()
233 require.Nil(t, err)
234 rollupEvents, _, err = c.RollupEventsByBlock(blockNum)
235 require.Nil(t, err)
236
237 rollupForgeBatchArgs1, sender, err := c.RollupForgeBatchArgs(rollupEvents.ForgeBatch[0].EthTxHash)
238 require.Nil(t, err)
239 assert.Equal(t, *c.addr, *sender)
240 assert.Equal(t, rollupForgeBatchArgs0, rollupForgeBatchArgs1)
241}
242
243type keys struct {
244 BJJSecretKey *babyjub.PrivateKey
245 BJJPublicKey *babyjub.PublicKey
246 Addr ethCommon.Address
247}
248
249func genKeys(i int64) *keys {
250 i++ // i = 0 doesn't work for the ecdsa key generation
251 var sk babyjub.PrivateKey
252 binary.LittleEndian.PutUint64(sk[:], uint64(i))
253
254 // eth address
255 var key ecdsa.PrivateKey
256 key.D = big.NewInt(i) // only for testing
257 key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
258 key.Curve = ethCrypto.S256()
259 addr := ethCrypto.PubkeyToAddress(key.PublicKey)
260
261 return &keys{
262 BJJSecretKey: &sk,
263 BJJPublicKey: sk.Public(),
264 Addr: addr,
265 }
266}