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.

353 lines
12 KiB

  1. package transakcio
  2. import (
  3. "crypto/ecdsa"
  4. "fmt"
  5. "math/big"
  6. "strconv"
  7. "strings"
  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. )
  14. // TestContext contains the data of the test
  15. type TestContext struct {
  16. Instructions []instruction
  17. accountsNames []string
  18. Users map[string]*User
  19. lastRegisteredTokenID common.TokenID
  20. l1CreatedAccounts map[string]*Account
  21. }
  22. // NewTestContext returns a new TestContext
  23. func NewTestContext() *TestContext {
  24. return &TestContext{
  25. Users: make(map[string]*User),
  26. l1CreatedAccounts: make(map[string]*Account),
  27. }
  28. }
  29. // Account contains the data related to the account for a specific TokenID of a User
  30. type Account struct {
  31. Idx common.Idx
  32. Nonce common.Nonce
  33. }
  34. // User contains the data related to a testing user
  35. type User struct {
  36. BJJ *babyjub.PrivateKey
  37. Addr ethCommon.Address
  38. Accounts map[common.TokenID]*Account
  39. }
  40. // BlockData contains the information of a Block
  41. type BlockData struct {
  42. // block *common.Block // ethereum block
  43. // L1UserTxs that were submitted in the block
  44. L1UserTxs []common.L1Tx
  45. Batches []BatchData
  46. RegisteredTokens []common.Token
  47. }
  48. // BatchData contains the information of a Batch
  49. type BatchData struct {
  50. L1Batch bool // TODO: Remove once Batch.ForgeL1TxsNum is a pointer
  51. // L1UserTxs that were forged in the batch
  52. L1UserTxs []common.L1Tx
  53. L1CoordinatorTxs []common.L1Tx
  54. L2Txs []common.L2Tx
  55. CreatedAccounts []common.Account
  56. ExitTree []common.ExitInfo
  57. Batch *common.Batch
  58. }
  59. // GenerateBlocks returns an array of BlockData for a given set. It uses the
  60. // accounts (keys & nonces) of the TestContext.
  61. func (tc *TestContext) GenerateBlocks(set string) ([]BlockData, error) {
  62. parser := newParser(strings.NewReader(set))
  63. parsedSet, err := parser.parse()
  64. if err != nil {
  65. return nil, err
  66. }
  67. tc.Instructions = parsedSet.instructions
  68. tc.accountsNames = parsedSet.accounts
  69. tc.generateKeys(tc.accountsNames)
  70. var blocks []BlockData
  71. currBatchNum := 0
  72. var currBlock BlockData
  73. var currBatch BatchData
  74. idx := 256
  75. for _, inst := range parsedSet.instructions {
  76. switch inst.typ {
  77. case common.TxTypeCreateAccountDeposit, common.TxTypeCreateAccountDepositTransfer, txTypeCreateAccountDepositCoordinator:
  78. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  79. return nil, err
  80. }
  81. tx := common.L1Tx{
  82. // TxID
  83. FromEthAddr: tc.Users[inst.from].Addr,
  84. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  85. TokenID: inst.tokenID,
  86. LoadAmount: big.NewInt(int64(inst.loadAmount)),
  87. Type: inst.typ,
  88. }
  89. if tc.Users[inst.from].Accounts[inst.tokenID] == nil { // if account is not set yet, set it and increment idx
  90. tc.Users[inst.from].Accounts[inst.tokenID] = &Account{
  91. Idx: common.Idx(idx),
  92. Nonce: common.Nonce(0),
  93. }
  94. tc.l1CreatedAccounts[idxTokenIDToString(inst.from, inst.tokenID)] = tc.Users[inst.from].Accounts[inst.tokenID]
  95. idx++
  96. }
  97. if inst.typ == common.TxTypeCreateAccountDepositTransfer {
  98. tx.Amount = big.NewInt(int64(inst.amount))
  99. }
  100. if inst.typ == txTypeCreateAccountDepositCoordinator {
  101. tx.Type = common.TxTypeCreateAccountDeposit // as txTypeCreateAccountDepositCoordinator is not valid oustide Transakcio package
  102. currBatch.L1CoordinatorTxs = append(currBatch.L1CoordinatorTxs, tx)
  103. } else {
  104. currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx)
  105. }
  106. case common.TxTypeDeposit, common.TxTypeDepositTransfer:
  107. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  108. return nil, err
  109. }
  110. if tc.Users[inst.from].Accounts[inst.tokenID] == nil {
  111. return nil, fmt.Errorf("Deposit at User %s for TokenID %d while account not created yet", inst.from, inst.tokenID)
  112. }
  113. tx := common.L1Tx{
  114. // TxID
  115. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  116. FromEthAddr: tc.Users[inst.from].Addr,
  117. FromBJJ: tc.Users[inst.from].BJJ.Public(),
  118. TokenID: inst.tokenID,
  119. LoadAmount: big.NewInt(int64(inst.loadAmount)),
  120. Type: inst.typ,
  121. }
  122. if tc.Users[inst.from].Accounts[inst.tokenID].Idx == common.Idx(0) {
  123. // if account.Idx is not set yet, set it and increment idx
  124. tc.Users[inst.from].Accounts[inst.tokenID].Idx = common.Idx(idx)
  125. tc.l1CreatedAccounts[idxTokenIDToString(inst.from, inst.tokenID)] = tc.Users[inst.from].Accounts[inst.tokenID]
  126. idx++
  127. }
  128. if inst.typ == common.TxTypeDepositTransfer {
  129. tx.Amount = big.NewInt(int64(inst.amount))
  130. // if ToIdx is not set yet, set it and increment idx
  131. if tc.Users[inst.to].Accounts[inst.tokenID].Idx == common.Idx(0) {
  132. tc.Users[inst.to].Accounts[inst.tokenID].Idx = common.Idx(idx)
  133. tc.l1CreatedAccounts[idxTokenIDToString(inst.to, inst.tokenID)] = tc.Users[inst.to].Accounts[inst.tokenID]
  134. tx.ToIdx = common.Idx(idx)
  135. idx++
  136. } else {
  137. // if Idx account of To already exist, use it for ToIdx
  138. tx.ToIdx = tc.Users[inst.to].Accounts[inst.tokenID].Idx
  139. }
  140. }
  141. currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx)
  142. case common.TxTypeTransfer:
  143. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  144. return nil, err
  145. }
  146. if tc.Users[inst.from].Accounts[inst.tokenID] == nil {
  147. return nil, fmt.Errorf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID)
  148. }
  149. // if account of receiver does not exist, create a new CoordinatorL1Tx creating the account
  150. if _, ok := tc.l1CreatedAccounts[idxTokenIDToString(inst.to, inst.tokenID)]; !ok {
  151. return nil, fmt.Errorf("Can not create Transfer for a non existing account. Batch %d, Instruction: %s", currBatchNum, inst)
  152. }
  153. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  154. tx := common.L2Tx{
  155. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  156. ToIdx: tc.Users[inst.to].Accounts[inst.tokenID].Idx,
  157. Amount: big.NewInt(int64(inst.amount)),
  158. Fee: common.FeeSelector(inst.fee),
  159. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  160. Type: common.TxTypeTransfer,
  161. }
  162. nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx())
  163. if err != nil {
  164. return nil, err
  165. }
  166. tx = nTx.L2Tx()
  167. tx.BatchNum = common.BatchNum(currBatchNum) // when converted to PoolL2Tx BatchNum parameter is lost
  168. currBatch.L2Txs = append(currBatch.L2Txs, tx)
  169. case common.TxTypeExit:
  170. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  171. return nil, err
  172. }
  173. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  174. tx := common.L2Tx{
  175. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  176. ToIdx: common.Idx(1), // as is an Exit
  177. Amount: big.NewInt(int64(inst.amount)),
  178. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  179. Type: common.TxTypeExit,
  180. }
  181. nTx, err := common.NewPoolL2Tx(tx.PoolL2Tx())
  182. if err != nil {
  183. return nil, err
  184. }
  185. tx = nTx.L2Tx()
  186. currBatch.L2Txs = append(currBatch.L2Txs, tx)
  187. case common.TxTypeForceExit:
  188. if err := tc.checkIfTokenIsRegistered(inst); err != nil {
  189. return nil, err
  190. }
  191. tx := common.L1Tx{
  192. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  193. ToIdx: common.Idx(1), // as is an Exit
  194. TokenID: inst.tokenID,
  195. Amount: big.NewInt(int64(inst.amount)),
  196. Type: common.TxTypeExit,
  197. }
  198. currBatch.L1UserTxs = append(currBatch.L1UserTxs, tx)
  199. case typeNewBatch:
  200. currBlock.Batches = append(currBlock.Batches, currBatch)
  201. currBatchNum++
  202. currBatch = BatchData{}
  203. case typeNewBlock:
  204. currBlock.Batches = append(currBlock.Batches, currBatch)
  205. currBatchNum++
  206. currBatch = BatchData{}
  207. blocks = append(blocks, currBlock)
  208. currBlock = BlockData{}
  209. case typeRegisterToken:
  210. newToken := common.Token{
  211. TokenID: inst.tokenID,
  212. EthBlockNum: int64(len(blocks)),
  213. }
  214. if inst.tokenID != tc.lastRegisteredTokenID+1 {
  215. return nil, fmt.Errorf("RegisterToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", tc.lastRegisteredTokenID+1, inst.tokenID)
  216. }
  217. tc.lastRegisteredTokenID++
  218. currBlock.RegisteredTokens = append(currBlock.RegisteredTokens, newToken)
  219. default:
  220. return nil, fmt.Errorf("Unexpected type: %s", inst.typ)
  221. }
  222. }
  223. currBlock.Batches = append(currBlock.Batches, currBatch)
  224. blocks = append(blocks, currBlock)
  225. return blocks, nil
  226. }
  227. func (tc *TestContext) checkIfTokenIsRegistered(inst instruction) error {
  228. if inst.tokenID > tc.lastRegisteredTokenID {
  229. return fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.lastRegisteredTokenID)
  230. }
  231. return nil
  232. }
  233. // GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It
  234. // uses the accounts (keys & nonces) of the TestContext.
  235. func (tc *TestContext) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
  236. parser := newParser(strings.NewReader(set))
  237. parsedSet, err := parser.parse()
  238. if err != nil {
  239. return nil, err
  240. }
  241. tc.Instructions = parsedSet.instructions
  242. tc.accountsNames = parsedSet.accounts
  243. tc.generateKeys(tc.accountsNames)
  244. txs := []common.PoolL2Tx{}
  245. for _, inst := range tc.Instructions {
  246. switch inst.typ {
  247. case common.TxTypeTransfer:
  248. if tc.Users[inst.from].Accounts[inst.tokenID] == nil {
  249. return nil, fmt.Errorf("Transfer from User %s for TokenID %d while account not created yet", inst.from, inst.tokenID)
  250. }
  251. if tc.Users[inst.to].Accounts[inst.tokenID] == nil {
  252. return nil, fmt.Errorf("Transfer to User %s for TokenID %d while account not created yet", inst.to, inst.tokenID)
  253. }
  254. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  255. // if account of receiver does not exist, don't use
  256. // ToIdx, and use only ToEthAddr & ToBJJ
  257. tx := common.PoolL2Tx{
  258. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  259. ToIdx: tc.Users[inst.to].Accounts[inst.tokenID].Idx,
  260. ToEthAddr: tc.Users[inst.to].Addr,
  261. ToBJJ: tc.Users[inst.to].BJJ.Public(),
  262. TokenID: inst.tokenID,
  263. Amount: big.NewInt(int64(inst.amount)),
  264. Fee: common.FeeSelector(inst.fee),
  265. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  266. State: common.PoolL2TxStatePending,
  267. Timestamp: time.Now(),
  268. RqToEthAddr: common.EmptyAddr,
  269. RqToBJJ: nil,
  270. Type: common.TxTypeTransfer,
  271. }
  272. nTx, err := common.NewPoolL2Tx(&tx)
  273. if err != nil {
  274. return nil, err
  275. }
  276. tx = *nTx
  277. // perform signature and set it to tx.Signature
  278. toSign, err := tx.HashToSign()
  279. if err != nil {
  280. return nil, err
  281. }
  282. sig := tc.Users[inst.to].BJJ.SignPoseidon(toSign)
  283. tx.Signature = sig
  284. txs = append(txs, tx)
  285. case common.TxTypeExit:
  286. tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
  287. tx := common.PoolL2Tx{
  288. FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
  289. ToIdx: common.Idx(1), // as is an Exit
  290. TokenID: inst.tokenID,
  291. Amount: big.NewInt(int64(inst.amount)),
  292. Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
  293. Type: common.TxTypeExit,
  294. }
  295. txs = append(txs, tx)
  296. default:
  297. return nil, fmt.Errorf("instruction type unrecognized: %s", inst.typ)
  298. }
  299. }
  300. return txs, nil
  301. }
  302. // generateKeys generates BabyJubJub & Address keys for the given list of
  303. // account names in a deterministic way. This means, that for the same given
  304. // 'accNames' in a certain order, the keys will be always the same.
  305. func (tc *TestContext) generateKeys(accNames []string) {
  306. for i := 1; i < len(accNames)+1; i++ {
  307. if _, ok := tc.Users[accNames[i-1]]; ok {
  308. // account already created
  309. continue
  310. }
  311. // babyjubjub key
  312. var sk babyjub.PrivateKey
  313. copy(sk[:], []byte(strconv.Itoa(i))) // only for testing
  314. // eth address
  315. var key ecdsa.PrivateKey
  316. key.D = big.NewInt(int64(i)) // only for testing
  317. key.PublicKey.X, key.PublicKey.Y = ethCrypto.S256().ScalarBaseMult(key.D.Bytes())
  318. key.Curve = ethCrypto.S256()
  319. addr := ethCrypto.PubkeyToAddress(key.PublicKey)
  320. u := User{
  321. BJJ: &sk,
  322. Addr: addr,
  323. Accounts: make(map[common.TokenID]*Account),
  324. }
  325. tc.Users[accNames[i-1]] = &u
  326. }
  327. }