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.

186 lines
6.4 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. // Account contains the data related to a testing account
  16. type Account struct {
  17. BJJ *babyjub.PrivateKey
  18. Addr ethCommon.Address
  19. Idx common.Idx
  20. Nonce common.Nonce
  21. }
  22. // GenerateKeys generates BabyJubJub & Address keys for the given list of
  23. // account names in a deterministic way. This means, that for the same given
  24. // 'accNames' the keys will be always the same.
  25. func GenerateKeys(t *testing.T, accNames []string) map[string]*Account {
  26. acc := make(map[string]*Account)
  27. for i := 1; i < len(accNames)+1; i++ {
  28. // babyjubjub key
  29. var sk babyjub.PrivateKey
  30. copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
  31. // eth address
  32. var key ecdsa.PrivateKey
  33. key.D = big.NewInt(int64(i)) // only for testing
  34. key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
  35. key.Curve = ethCrypto.S256()
  36. addr := ethCrypto.PubkeyToAddress(key.PublicKey)
  37. a := Account{
  38. BJJ: &sk,
  39. Addr: addr,
  40. Nonce: 0,
  41. }
  42. acc[accNames[i-1]] = &a
  43. }
  44. return acc
  45. }
  46. // GenerateTestTxs generates L1Tx & PoolL2Tx in a deterministic way for the
  47. // given Instructions.
  48. func GenerateTestTxs(t *testing.T, instructions Instructions) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
  49. accounts := GenerateKeys(t, instructions.Accounts)
  50. l1CreatedAccounts := make(map[string]*Account)
  51. var batchL1Txs []*common.L1Tx
  52. var batchCoordinatorL1Txs []*common.L1Tx
  53. var batchPoolL2Txs []*common.PoolL2Tx
  54. var l1Txs [][]*common.L1Tx
  55. var coordinatorL1Txs [][]*common.L1Tx
  56. var poolL2Txs [][]*common.PoolL2Tx
  57. idx := 256
  58. for _, inst := range instructions.Instructions {
  59. switch inst.Type {
  60. case common.TxTypeCreateAccountDeposit:
  61. tx := common.L1Tx{
  62. // TxID
  63. FromEthAddr: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Addr,
  64. FromBJJ: accounts[idxTokenIDToString(inst.From, inst.TokenID)].BJJ.Public(),
  65. TokenID: inst.TokenID,
  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. Timestamp: time.Now(),
  101. BatchNum: common.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. nTx, err := common.NewPoolL2Tx(&tx)
  107. if err != nil {
  108. panic(err)
  109. }
  110. tx = *nTx
  111. // perform signature and set it to tx.Signature
  112. toSign, err := tx.HashToSign()
  113. if err != nil {
  114. panic(err)
  115. }
  116. sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
  117. tx.Signature = sig
  118. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
  119. batchPoolL2Txs = append(batchPoolL2Txs, &tx)
  120. case common.TxTypeExit, common.TxTypeForceExit:
  121. tx := common.L1Tx{
  122. FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
  123. ToIdx: common.Idx(1), // as is an Exit
  124. TokenID: inst.TokenID,
  125. Amount: big.NewInt(int64(inst.Amount)),
  126. Type: common.TxTypeExit,
  127. }
  128. batchL1Txs = append(batchL1Txs, &tx)
  129. case TypeNewBatch:
  130. l1Txs = append(l1Txs, batchL1Txs)
  131. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  132. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  133. batchL1Txs = []*common.L1Tx{}
  134. batchCoordinatorL1Txs = []*common.L1Tx{}
  135. batchPoolL2Txs = []*common.PoolL2Tx{}
  136. default:
  137. continue
  138. }
  139. }
  140. l1Txs = append(l1Txs, batchL1Txs)
  141. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  142. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  143. tokens := []common.Token{}
  144. for i := 0; i < len(poolL2Txs); i++ {
  145. for j := 0; j < len(poolL2Txs[i]); j++ {
  146. id := poolL2Txs[i][j].TokenID
  147. found := false
  148. for k := 0; k < len(tokens); k++ {
  149. if tokens[k].TokenID == id {
  150. found = true
  151. break
  152. }
  153. }
  154. if !found {
  155. tokens = append(tokens, common.Token{
  156. TokenID: id,
  157. EthBlockNum: 1,
  158. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))),
  159. })
  160. }
  161. }
  162. }
  163. return l1Txs, coordinatorL1Txs, poolL2Txs, tokens
  164. }
  165. // GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
  166. // Instructions code
  167. func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx, []common.Token) {
  168. parser := NewParser(strings.NewReader(set))
  169. instructions, err := parser.Parse()
  170. require.Nil(t, err)
  171. return GenerateTestTxs(t, instructions)
  172. }