arnaucube
arnaucube/hermez-nodePublic Self-hosted repository
hermez-node/common/l1tx_test.go
common/l1tx_test.goRaw
  1package common
  2
  3import (
  4	"crypto/ecdsa"
  5	"encoding/hex"
  6	"log"
  7	"math/big"
  8	"testing"
  9
 10	ethCommon "github.com/ethereum/go-ethereum/common"
 11	"github.com/ethereum/go-ethereum/crypto"
 12	"github.com/iden3/go-iden3-crypto/babyjub"
 13	"github.com/iden3/go-iden3-crypto/utils"
 14	"github.com/stretchr/testify/assert"
 15	"github.com/stretchr/testify/require"
 16)
 17
 18func TestNewL1UserTx(t *testing.T) {
 19	toForge := int64(123456)
 20	l1Tx := &L1Tx{
 21		ToForgeL1TxsNum: &toForge,
 22		Position:        71,
 23		UserOrigin:      true,
 24		ToIdx:           301,
 25		TokenID:         5,
 26		Amount:          big.NewInt(1),
 27		DepositAmount:   big.NewInt(2),
 28		FromIdx:         Idx(300),
 29	}
 30	l1Tx, err := NewL1Tx(l1Tx)
 31	assert.NoError(t, err)
 32	assert.Equal(t, "0x00a6cbae3b8661fb75b0919ca6605a02cfb04d9c6dd16870fa0fcdf01befa32768", l1Tx.TxID.String())
 33}
 34
 35func TestNewL1CoordinatorTx(t *testing.T) {
 36	batchNum := BatchNum(51966)
 37	l1Tx := &L1Tx{
 38		Position:      88,
 39		UserOrigin:    false,
 40		ToIdx:         301,
 41		TokenID:       5,
 42		Amount:        big.NewInt(1),
 43		DepositAmount: big.NewInt(2),
 44		FromIdx:       Idx(300),
 45		BatchNum:      &batchNum,
 46	}
 47	l1Tx, err := NewL1Tx(l1Tx)
 48	assert.NoError(t, err)
 49	assert.Equal(t, "0x01274482d73df4dab34a1b6740adfca347a462513aa14e82f27b12f818d1b68c84", l1Tx.TxID.String())
 50}
 51
 52func TestL1TxCompressedData(t *testing.T) {
 53	// test vectors values generated from javascript implementation (using
 54	// PoolL2Tx values)
 55	amount, ok := new(big.Int).SetString("343597383670000000000000000000000000000000", 10)
 56	require.True(t, ok)
 57	tx := L1Tx{
 58		FromIdx: (1 << 48) - 1,
 59		ToIdx:   (1 << 48) - 1,
 60		Amount:  amount,
 61		TokenID: (1 << 32) - 1,
 62	}
 63	txCompressedData, err := tx.TxCompressedData(uint16((1 << 16) - 1))
 64	assert.NoError(t, err)
 65	expectedStr := "ffffffffffffffffffffffffffffffffffffc60be60f"
 66	assert.Equal(t, expectedStr, hex.EncodeToString(txCompressedData.Bytes()))
 67
 68	tx = L1Tx{
 69		FromIdx: 0,
 70		ToIdx:   0,
 71		Amount:  big.NewInt(0),
 72		TokenID: 0,
 73	}
 74	txCompressedData, err = tx.TxCompressedData(uint16(0))
 75	assert.NoError(t, err)
 76	expectedStr = "c60be60f"
 77	assert.Equal(t, expectedStr, hex.EncodeToString(txCompressedData.Bytes()))
 78
 79	amount, ok = new(big.Int).SetString("63000000000000000", 10)
 80	require.True(t, ok)
 81	tx = L1Tx{
 82		FromIdx: 324,
 83		ToIdx:   256,
 84		Amount:  amount,
 85		TokenID: 123,
 86	}
 87	txCompressedData, err = tx.TxCompressedData(uint16(1))
 88	assert.NoError(t, err)
 89	expectedStr = "7b0000000001000000000001440001c60be60f"
 90	assert.Equal(t, expectedStr, hex.EncodeToString(txCompressedData.Bytes()))
 91
 92	tx = L1Tx{
 93		FromIdx: 1,
 94		ToIdx:   2,
 95		TokenID: 3,
 96	}
 97	txCompressedData, err = tx.TxCompressedData(uint16(0))
 98	assert.NoError(t, err)
 99	expectedStr = "030000000000020000000000010000c60be60f"
100	assert.Equal(t, expectedStr, hex.EncodeToString(txCompressedData.Bytes()))
101}
102
103func TestBytesDataAvailability(t *testing.T) {
104	// test vectors values generated from javascript implementation
105	amount, ok := new(big.Int).SetString("343597383670000000000000000000000000000000", 10)
106	require.True(t, ok)
107	tx := L1Tx{
108		ToIdx:           (1 << 16) - 1,
109		FromIdx:         (1 << 16) - 1,
110		EffectiveAmount: amount,
111	}
112	txCompressedData, err := tx.BytesDataAvailability(16)
113	assert.NoError(t, err)
114	assert.Equal(t, "ffffffffffffffffff00", hex.EncodeToString(txCompressedData))
115	l1tx, err := L1TxFromDataAvailability(txCompressedData, 16)
116	require.NoError(t, err)
117	assert.Equal(t, tx.FromIdx, l1tx.FromIdx)
118	assert.Equal(t, tx.ToIdx, l1tx.ToIdx)
119	assert.Equal(t, tx.EffectiveAmount, l1tx.EffectiveAmount)
120
121	tx = L1Tx{
122		ToIdx:           (1 << 32) - 1,
123		FromIdx:         (1 << 32) - 1,
124		EffectiveAmount: amount,
125	}
126	txCompressedData, err = tx.BytesDataAvailability(32)
127	assert.NoError(t, err)
128	assert.Equal(t, "ffffffffffffffffffffffffff00", hex.EncodeToString(txCompressedData))
129	l1tx, err = L1TxFromDataAvailability(txCompressedData, 32)
130	require.NoError(t, err)
131	assert.Equal(t, tx.FromIdx, l1tx.FromIdx)
132	assert.Equal(t, tx.ToIdx, l1tx.ToIdx)
133	assert.Equal(t, tx.EffectiveAmount, l1tx.EffectiveAmount)
134
135	tx = L1Tx{
136		ToIdx:           0,
137		FromIdx:         0,
138		EffectiveAmount: big.NewInt(0),
139	}
140	txCompressedData, err = tx.BytesDataAvailability(32)
141	assert.NoError(t, err)
142	assert.Equal(t, "0000000000000000000000000000", hex.EncodeToString(txCompressedData))
143	l1tx, err = L1TxFromDataAvailability(txCompressedData, 32)
144	require.NoError(t, err)
145	assert.Equal(t, tx.FromIdx, l1tx.FromIdx)
146	assert.Equal(t, tx.ToIdx, l1tx.ToIdx)
147	assert.Equal(t, tx.EffectiveAmount, l1tx.EffectiveAmount)
148
149	tx = L1Tx{
150		ToIdx:           635,
151		FromIdx:         296,
152		EffectiveAmount: big.NewInt(1000000000000000000),
153	}
154	txCompressedData, err = tx.BytesDataAvailability(32)
155	assert.NoError(t, err)
156	assert.Equal(t, "000001280000027b42540be40000", hex.EncodeToString(txCompressedData))
157	l1tx, err = L1TxFromDataAvailability(txCompressedData, 32)
158	require.NoError(t, err)
159	assert.Equal(t, tx.FromIdx, l1tx.FromIdx)
160	assert.Equal(t, tx.ToIdx, l1tx.ToIdx)
161	assert.Equal(t, tx.EffectiveAmount, l1tx.EffectiveAmount)
162}
163
164func TestL1userTxByteParsers(t *testing.T) {
165	var pkComp babyjub.PublicKeyComp
166	pkCompL := []byte("0x56ca90f80d7c374ae7485e9bcc47d4ac399460948da6aeeb899311097925a72c")
167	err := pkComp.UnmarshalText(pkCompL)
168	require.NoError(t, err)
169
170	l1Tx := &L1Tx{
171		UserOrigin:    true,
172		ToIdx:         3,
173		TokenID:       5,
174		Amount:        big.NewInt(1),
175		DepositAmount: big.NewInt(2),
176		FromIdx:       2,
177		FromBJJ:       pkComp,
178		FromEthAddr:   ethCommon.HexToAddress("0xc58d29fA6e86E4FAe04DDcEd660d45BCf3Cb2370"),
179	}
180
181	encodedData, err := l1Tx.BytesUser()
182	require.NoError(t, err)
183	decodedData, err := L1UserTxFromBytes(encodedData)
184	require.NoError(t, err)
185	assert.Equal(t, l1Tx, decodedData)
186	encodedData2, err := decodedData.BytesUser()
187	require.NoError(t, err)
188	assert.Equal(t, encodedData, encodedData2)
189
190	// expect error if length!=68
191	_, err = L1UserTxFromBytes(encodedData[:66])
192	require.NotNil(t, err)
193	_, err = L1UserTxFromBytes([]byte{})
194	require.NotNil(t, err)
195	_, err = L1UserTxFromBytes(nil)
196	require.NotNil(t, err)
197}
198
199func TestL1TxByteParsersCompatibility(t *testing.T) {
200	// Data from compatibility test
201	var pkComp babyjub.PublicKeyComp
202	pkCompB, err := hex.DecodeString("0dd02deb2c81068e7a0f7e327df80b4ab79ee1f41a7def613e73a20c32eece5a")
203	require.NoError(t, err)
204	pkCompL := SwapEndianness(pkCompB)
205	err = pkComp.UnmarshalText([]byte(hex.EncodeToString(pkCompL)))
206	require.NoError(t, err)
207
208	depositAmount := new(big.Int)
209	depositAmount.SetString("100000000000000000000", 10)
210	l1Tx := &L1Tx{
211		ToIdx:         87865485,
212		TokenID:       2098076,
213		Amount:        big.NewInt(2400000000000000000),
214		DepositAmount: depositAmount,
215		FromIdx:       Idx(29767899),
216		FromBJJ:       pkComp,
217		FromEthAddr:   ethCommon.HexToAddress("0x85dab5b9e2e361d0c208d77be90efcc0439b0a53"),
218		UserOrigin:    true,
219	}
220
221	encodedData, err := l1Tx.BytesUser()
222	require.NoError(t, err)
223	expected := "85dab5b9e2e361d0c208d77be90efcc0439b0a530dd02deb2c81068e7a0f7e327df80b4ab79ee1f41a7def613e73a20c32eece5a000001c638db52540be400459682f0000020039c0000053cb88d"
224	assert.Equal(t, expected, hex.EncodeToString(encodedData))
225}
226
227func TestL1CoordinatorTxByteParsers(t *testing.T) {
228	hermezAddress := ethCommon.HexToAddress("0xD6C850aeBFDC46D7F4c207e445cC0d6B0919BDBe")
229	chainID := big.NewInt(1337)
230	chainIDBytes := ethCommon.LeftPadBytes(chainID.Bytes(), 2)
231
232	privateKey, err := crypto.HexToECDSA("fad9c8855b740a0b7ed4c221dbad0f33a83a49cad6b3fe8d5817ac83d38b6a19")
233	require.NoError(t, err)
234
235	publicKey := privateKey.Public()
236	publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
237	if !ok {
238		log.Fatal("error casting public key to ECDSA")
239	}
240	publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)
241	pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes)
242	require.NoError(t, err)
243	fromEthAddr := crypto.PubkeyToAddress(*pubKey)
244	var pkComp babyjub.PublicKeyComp
245	pkCompL := []byte("56ca90f80d7c374ae7485e9bcc47d4ac399460948da6aeeb899311097925a72c")
246	err = pkComp.UnmarshalText(pkCompL)
247	require.NoError(t, err)
248	bytesMessage1 := []byte("\x19Ethereum Signed Message:\n120")
249	bytesMessage2 := []byte("I authorize this babyjubjub key for hermez rollup account creation")
250
251	babyjubB := SwapEndianness(pkComp[:])
252	var data []byte
253	data = append(data, bytesMessage1...)
254	data = append(data, bytesMessage2...)
255	data = append(data, babyjubB[:]...)
256	data = append(data, chainIDBytes...)
257	data = append(data, hermezAddress.Bytes()...)
258	hash := crypto.Keccak256Hash(data)
259	signature, err := crypto.Sign(hash.Bytes(), privateKey)
260	require.NoError(t, err)
261	// Ethereum adds 27 to v
262	v := int(signature[64])
263	signature[64] = byte(v + 27)
264
265	l1Tx := &L1Tx{
266		TokenID:       231,
267		FromBJJ:       pkComp,
268		FromEthAddr:   fromEthAddr,
269		Amount:        big.NewInt(0),
270		DepositAmount: big.NewInt(0),
271	}
272
273	bytesCoordinatorL1, err := l1Tx.BytesCoordinatorTx(signature)
274	require.NoError(t, err)
275	l1txDecoded, err := L1CoordinatorTxFromBytes(bytesCoordinatorL1, chainID, hermezAddress)
276	require.NoError(t, err)
277	assert.Equal(t, l1Tx, l1txDecoded)
278	bytesCoordinatorL12, err := l1txDecoded.BytesCoordinatorTx(signature)
279	require.NoError(t, err)
280	assert.Equal(t, bytesCoordinatorL1, bytesCoordinatorL12)
281
282	// expect error if length!=68
283	_, err = L1CoordinatorTxFromBytes(bytesCoordinatorL1[:66], chainID, hermezAddress)
284	require.NotNil(t, err)
285	_, err = L1CoordinatorTxFromBytes([]byte{}, chainID, hermezAddress)
286	require.NotNil(t, err)
287	_, err = L1CoordinatorTxFromBytes(nil, chainID, hermezAddress)
288	require.NotNil(t, err)
289}
290
291func TestL1CoordinatorTxByteParsersCompatibility(t *testing.T) {
292	// Data from compatibility test
293	var signature []byte
294	r, err := hex.DecodeString("da71e5eb097e115405d84d1e7b464009b434b32c014a2df502d1f065ced8bc3b")
295	require.NoError(t, err)
296	s, err := hex.DecodeString("186d7122ff7f654cfed3156719774898d573900c86599a885a706dbdffe5ea8c")
297	require.NoError(t, err)
298	v, err := hex.DecodeString("1b")
299	require.NoError(t, err)
300
301	signature = append(signature, r[:]...)
302	signature = append(signature, s[:]...)
303	signature = append(signature, v[:]...)
304
305	var pkComp babyjub.PublicKeyComp
306	pkCompB, err := hex.DecodeString("a2c2807ee39c3b3378738cff85a46a9465bb8fcf44ea597c33da9719be7c259c")
307	require.NoError(t, err)
308	pkCompL := SwapEndianness(pkCompB)
309	err = pkComp.UnmarshalText([]byte(hex.EncodeToString(pkCompL)))
310	require.NoError(t, err)
311	// Data from the compatibility test
312	require.NoError(t, err)
313	l1Tx := &L1Tx{
314		TokenID: 231,
315		FromBJJ: pkComp,
316	}
317
318	encodeData, err := l1Tx.BytesCoordinatorTx(signature)
319	require.NoError(t, err)
320
321	expected, err := utils.HexDecode("1b186d7122ff7f654cfed3156719774898d573900c86599a885a706dbdffe5ea8cda71e5eb097e115405d84d1e7b464009b434b32c014a2df502d1f065ced8bc3ba2c2807ee39c3b3378738cff85a46a9465bb8fcf44ea597c33da9719be7c259c000000e7")
322	require.NoError(t, err)
323
324	assert.Equal(t, expected, encodeData)
325}
326
327func TestL1TxID(t *testing.T) {
328	// L1UserTx
329	i64_1 := int64(1)
330	i64_2 := int64(2)
331	tx0 := L1Tx{
332		UserOrigin:      true,
333		ToForgeL1TxsNum: &i64_1,
334		Position:        1,
335	}
336	err := tx0.SetID()
337	require.NoError(t, err)
338	assert.Equal(t, TxIDPrefixL1UserTx, tx0.TxID[0])
339
340	// differ ToForgeL1TxsNum
341	tx1 := L1Tx{
342		UserOrigin:      true,
343		ToForgeL1TxsNum: &i64_2,
344		Position:        1,
345	}
346	err = tx1.SetID()
347	require.NoError(t, err)
348	assert.NotEqual(t, tx0.TxID, tx1.TxID)
349
350	// differ Position
351	tx1 = L1Tx{
352		UserOrigin:      true,
353		ToForgeL1TxsNum: &i64_1,
354		Position:        2,
355	}
356	err = tx1.SetID()
357	require.NoError(t, err)
358	assert.NotEqual(t, tx0.TxID, tx1.TxID)
359
360	// L1CoordinatorTx
361	bn1 := BatchNum(1)
362	bn2 := BatchNum(2)
363	tx0 = L1Tx{
364		UserOrigin: false,
365		BatchNum:   &bn1,
366		Position:   1,
367	}
368	err = tx0.SetID()
369	require.NoError(t, err)
370	assert.Equal(t, TxIDPrefixL1CoordTx, tx0.TxID[0])
371
372	// differ BatchNum
373	tx1 = L1Tx{
374		UserOrigin: false,
375		BatchNum:   &bn2,
376		Position:   1,
377	}
378	err = tx1.SetID()
379	require.NoError(t, err)
380	assert.NotEqual(t, tx0.TxID, tx1.TxID)
381
382	// differ Position
383	tx1 = L1Tx{
384		UserOrigin: false,
385		BatchNum:   &bn1,
386		Position:   2,
387	}
388	err = tx1.SetID()
389	require.NoError(t, err)
390	assert.NotEqual(t, tx0.TxID, tx1.TxID)
391}