You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

160 lines
5.7 KiB

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