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.

183 lines
6.3 KiB

  1. package test
  2. import (
  3. "crypto/ecdsa"
  4. "math/big"
  5. "strconv"
  6. "strings"
  7. "testing"
  8. ethCommon "github.com/ethereum/go-ethereum/common"
  9. ethCrypto "github.com/ethereum/go-ethereum/crypto"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/iden3/go-iden3-crypto/babyjub"
  12. "github.com/stretchr/testify/require"
  13. )
  14. // Account contains the data related to a testing account
  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, []common.Token) {
  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 := 256
  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. Amount: big.NewInt(0),
  66. LoadAmount: big.NewInt(int64(inst.Amount)),
  67. Type: common.TxTypeCreateAccountDeposit,
  68. }
  69. batchL1Txs = append(batchL1Txs, tx)
  70. if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx
  71. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx)
  72. l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)]
  73. idx++
  74. }
  75. case common.TxTypeTransfer:
  76. // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
  77. if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok {
  78. tx := common.L1Tx{
  79. FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
  80. FromBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  81. TokenID: inst.TokenID,
  82. LoadAmount: big.NewInt(int64(inst.Amount)),
  83. Type: common.TxTypeCreateAccountDeposit,
  84. }
  85. accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx)
  86. l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)]
  87. batchCoordinatorL1Txs = append(batchCoordinatorL1Txs, tx)
  88. idx++
  89. }
  90. tx := common.PoolL2Tx{
  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. RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
  101. RqToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  102. Type: common.TxTypeTransfer,
  103. }
  104. nTx, err := common.NewPoolL2Tx(&tx)
  105. if err != nil {
  106. panic(err)
  107. }
  108. tx = *nTx
  109. // perform signature and set it to tx.Signature
  110. toSign, err := tx.HashToSign()
  111. if err != nil {
  112. panic(err)
  113. }
  114. sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
  115. tx.Signature = sig
  116. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
  117. batchPoolL2Txs = append(batchPoolL2Txs, tx)
  118. case common.TxTypeExit, common.TxTypeForceExit:
  119. tx := common.L1Tx{
  120. FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
  121. ToIdx: common.Idx(1), // as is an Exit
  122. TokenID: inst.TokenID,
  123. Amount: big.NewInt(int64(inst.Amount)),
  124. Type: common.TxTypeExit,
  125. }
  126. batchL1Txs = append(batchL1Txs, tx)
  127. case TypeNewBatch:
  128. l1Txs = append(l1Txs, batchL1Txs)
  129. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  130. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  131. batchL1Txs = []common.L1Tx{}
  132. batchCoordinatorL1Txs = []common.L1Tx{}
  133. batchPoolL2Txs = []common.PoolL2Tx{}
  134. default:
  135. continue
  136. }
  137. }
  138. l1Txs = append(l1Txs, batchL1Txs)
  139. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  140. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  141. tokens := []common.Token{}
  142. for i := 0; i < len(poolL2Txs); i++ {
  143. for j := 0; j < len(poolL2Txs[i]); j++ {
  144. id := poolL2Txs[i][j].TokenID
  145. found := false
  146. for k := 0; k < len(tokens); k++ {
  147. if tokens[k].TokenID == id {
  148. found = true
  149. break
  150. }
  151. }
  152. if !found {
  153. tokens = append(tokens, common.Token{
  154. TokenID: id,
  155. EthBlockNum: 1,
  156. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))),
  157. })
  158. }
  159. }
  160. }
  161. return l1Txs, coordinatorL1Txs, poolL2Txs, tokens
  162. }
  163. // GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
  164. // Instructions code
  165. func GenerateTestTxsFromSet(t *testing.T, set string) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) {
  166. parser := NewParser(strings.NewReader(set))
  167. instructions, err := parser.Parse()
  168. require.Nil(t, err)
  169. return GenerateTestTxs(t, instructions)
  170. }