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.

194 lines
6.6 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. Amount: big.NewInt(0),
  67. LoadAmount: big.NewInt(int64(inst.Amount)),
  68. Type: common.TxTypeCreateAccountDeposit,
  69. }
  70. batchL1Txs = append(batchL1Txs, tx)
  71. if accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx == common.Idx(0) { // if account.Idx is not set yet, set it and increment idx
  72. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx = common.Idx(idx)
  73. l1CreatedAccounts[idxTokenIDToString(inst.From, inst.TokenID)] = accounts[idxTokenIDToString(inst.From, inst.TokenID)]
  74. idx++
  75. }
  76. case common.TxTypeTransfer:
  77. // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
  78. if _, ok := l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)]; !ok {
  79. tx := common.L1Tx{
  80. FromEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
  81. FromBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  82. TokenID: inst.TokenID,
  83. LoadAmount: big.NewInt(int64(inst.Amount)),
  84. Type: common.TxTypeCreateAccountDeposit,
  85. }
  86. accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx = common.Idx(idx)
  87. l1CreatedAccounts[idxTokenIDToString(inst.To, inst.TokenID)] = accounts[idxTokenIDToString(inst.To, inst.TokenID)]
  88. batchCoordinatorL1Txs = append(batchCoordinatorL1Txs, tx)
  89. idx++
  90. }
  91. toIdx := new(common.Idx)
  92. *toIdx = accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx
  93. toEthAddr := new(ethCommon.Address)
  94. *toEthAddr = accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr
  95. rqToEthAddr := new(ethCommon.Address)
  96. *rqToEthAddr = accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr
  97. tx := common.PoolL2Tx{
  98. FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
  99. ToIdx: toIdx,
  100. ToEthAddr: toEthAddr,
  101. ToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  102. TokenID: inst.TokenID,
  103. Amount: big.NewInt(int64(inst.Amount)),
  104. Fee: common.FeeSelector(inst.Fee),
  105. Nonce: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce,
  106. State: common.PoolL2TxStatePending,
  107. Timestamp: time.Now(),
  108. BatchNum: nil,
  109. RqToEthAddr: rqToEthAddr,
  110. RqToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  111. Type: common.TxTypeTransfer,
  112. }
  113. nTx, err := common.NewPoolL2Tx(&tx)
  114. if err != nil {
  115. panic(err)
  116. }
  117. tx = *nTx
  118. // perform signature and set it to tx.Signature
  119. toSign, err := tx.HashToSign()
  120. if err != nil {
  121. panic(err)
  122. }
  123. sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
  124. tx.Signature = sig
  125. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
  126. batchPoolL2Txs = append(batchPoolL2Txs, tx)
  127. case common.TxTypeExit, common.TxTypeForceExit:
  128. fromIdx := new(common.Idx)
  129. *fromIdx = accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx
  130. tx := common.L1Tx{
  131. FromIdx: fromIdx,
  132. ToIdx: common.Idx(1), // as is an Exit
  133. TokenID: inst.TokenID,
  134. Amount: big.NewInt(int64(inst.Amount)),
  135. Type: common.TxTypeExit,
  136. }
  137. batchL1Txs = append(batchL1Txs, tx)
  138. case TypeNewBatch:
  139. l1Txs = append(l1Txs, batchL1Txs)
  140. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  141. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  142. batchL1Txs = []common.L1Tx{}
  143. batchCoordinatorL1Txs = []common.L1Tx{}
  144. batchPoolL2Txs = []common.PoolL2Tx{}
  145. default:
  146. continue
  147. }
  148. }
  149. l1Txs = append(l1Txs, batchL1Txs)
  150. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  151. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  152. tokens := []common.Token{}
  153. for i := 0; i < len(poolL2Txs); i++ {
  154. for j := 0; j < len(poolL2Txs[i]); j++ {
  155. id := poolL2Txs[i][j].TokenID
  156. found := false
  157. for k := 0; k < len(tokens); k++ {
  158. if tokens[k].TokenID == id {
  159. found = true
  160. break
  161. }
  162. }
  163. if !found {
  164. tokens = append(tokens, common.Token{
  165. TokenID: id,
  166. EthBlockNum: 1,
  167. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i*10000 + j))),
  168. })
  169. }
  170. }
  171. }
  172. return l1Txs, coordinatorL1Txs, poolL2Txs, tokens
  173. }
  174. // GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
  175. // Instructions code
  176. func GenerateTestTxsFromSet(t *testing.T, set string) ([][]common.L1Tx, [][]common.L1Tx, [][]common.PoolL2Tx, []common.Token) {
  177. parser := NewParser(strings.NewReader(set))
  178. instructions, err := parser.Parse()
  179. require.Nil(t, err)
  180. return GenerateTestTxs(t, instructions)
  181. }