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.

163 lines
5.9 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) {
  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 := 1
  58. for i, 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. TxID: common.TxID([]byte{byte(i)}), // TODO this is for the moment, once TxID Hash is implemented use it
  92. FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
  93. ToIdx: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Idx,
  94. ToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
  95. ToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  96. TokenID: inst.TokenID,
  97. Amount: big.NewInt(int64(inst.Amount)),
  98. Fee: common.FeeSelector(inst.Fee),
  99. Nonce: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce,
  100. State: common.PoolL2TxStatePending,
  101. Timestamp: time.Now(),
  102. BatchNum: common.BatchNum(0),
  103. RqToEthAddr: accounts[idxTokenIDToString(inst.To, inst.TokenID)].Addr,
  104. RqToBJJ: accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.Public(),
  105. Type: common.TxTypeTransfer,
  106. }
  107. // perform signature and set it to tx.Signature
  108. toSign, err := tx.HashToSign()
  109. if err != nil {
  110. panic(err)
  111. }
  112. sig := accounts[idxTokenIDToString(inst.To, inst.TokenID)].BJJ.SignPoseidon(toSign)
  113. tx.Signature = sig
  114. accounts[idxTokenIDToString(inst.From, inst.TokenID)].Nonce++
  115. batchPoolL2Txs = append(batchPoolL2Txs, &tx)
  116. case common.TxTypeExit, common.TxTypeForceExit:
  117. tx := common.L1Tx{
  118. FromIdx: accounts[idxTokenIDToString(inst.From, inst.TokenID)].Idx,
  119. ToIdx: common.Idx(1), // as is an Exit
  120. TokenID: inst.TokenID,
  121. Amount: big.NewInt(int64(inst.Amount)),
  122. Type: common.TxTypeExit,
  123. }
  124. batchL1Txs = append(batchL1Txs, &tx)
  125. case TypeNewBatch:
  126. l1Txs = append(l1Txs, batchL1Txs)
  127. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  128. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  129. batchL1Txs = []*common.L1Tx{}
  130. batchCoordinatorL1Txs = []*common.L1Tx{}
  131. batchPoolL2Txs = []*common.PoolL2Tx{}
  132. default:
  133. continue
  134. }
  135. }
  136. l1Txs = append(l1Txs, batchL1Txs)
  137. coordinatorL1Txs = append(coordinatorL1Txs, batchCoordinatorL1Txs)
  138. poolL2Txs = append(poolL2Txs, batchPoolL2Txs)
  139. return l1Txs, coordinatorL1Txs, poolL2Txs
  140. }
  141. // GenerateTestTxsFromSet reurns the L1 & L2 transactions for a given Set of
  142. // Instructions code
  143. func GenerateTestTxsFromSet(t *testing.T, set string) ([][]*common.L1Tx, [][]*common.L1Tx, [][]*common.PoolL2Tx) {
  144. parser := NewParser(strings.NewReader(set))
  145. instructions, err := parser.Parse()
  146. require.Nil(t, err)
  147. return GenerateTestTxs(t, instructions)
  148. }