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.

467 lines
13 KiB

  1. package test
  2. import (
  3. "errors"
  4. "fmt"
  5. "math"
  6. "math/big"
  7. "strconv"
  8. "time"
  9. ethCommon "github.com/ethereum/go-ethereum/common"
  10. "github.com/hermeznetwork/hermez-node/common"
  11. "github.com/iden3/go-iden3-crypto/babyjub"
  12. "github.com/iden3/go-merkletree"
  13. )
  14. // WARNING: the generators in this file doesn't necessary follow the protocol
  15. // they are intended to check that the parsers between struct <==> DB are correct
  16. // GenBlocks generates block from, to block numbers. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  17. func GenBlocks(from, to int64) []common.Block {
  18. var blocks []common.Block
  19. for i := from; i < to; i++ {
  20. blocks = append(blocks, common.Block{
  21. EthBlockNum: i,
  22. //nolint:gomnd
  23. Timestamp: time.Now().Add(time.Second * 13).UTC(),
  24. Hash: ethCommon.BigToHash(big.NewInt(int64(i))),
  25. })
  26. }
  27. return blocks
  28. }
  29. // GenTokens generates tokens. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  30. func GenTokens(nTokens int, blocks []common.Block) []common.Token {
  31. tokens := []common.Token{}
  32. for i := 0; i < nTokens; i++ {
  33. token := common.Token{
  34. TokenID: common.TokenID(i),
  35. Name: fmt.Sprint(i),
  36. Symbol: fmt.Sprint(i),
  37. Decimals: uint64(i),
  38. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  39. EthAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
  40. }
  41. if i%2 == 0 {
  42. usd := 3.0
  43. token.USD = &usd
  44. now := time.Now()
  45. token.USDUpdate = &now
  46. }
  47. tokens = append(tokens, token)
  48. }
  49. return tokens
  50. }
  51. // GenBatches generates batches. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  52. func GenBatches(nBatches int, blocks []common.Block) []common.Batch {
  53. batches := []common.Batch{}
  54. collectedFees := make(map[common.TokenID]*big.Int)
  55. for i := 0; i < 64; i++ {
  56. collectedFees[common.TokenID(i)] = big.NewInt(int64(i))
  57. }
  58. for i := 0; i < nBatches; i++ {
  59. batch := common.Batch{
  60. BatchNum: common.BatchNum(i + 1),
  61. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  62. //nolint:gomnd
  63. ForgerAddr: ethCommon.BigToAddress(big.NewInt(6886723)),
  64. CollectedFees: collectedFees,
  65. StateRoot: common.Hash([]byte("duhdqlwiucgwqeiu")),
  66. //nolint:gomnd
  67. NumAccounts: 30,
  68. ExitRoot: common.Hash([]byte("tykertheuhtgenuer3iuw3b")),
  69. SlotNum: common.SlotNum(i),
  70. }
  71. if i%2 == 0 {
  72. batch.ForgeL1TxsNum = int64(i)
  73. }
  74. batches = append(batches, batch)
  75. }
  76. return batches
  77. }
  78. // GenAccounts generates accounts. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  79. func GenAccounts(totalAccounts, userAccounts int, tokens []common.Token, userAddr *ethCommon.Address, userBjj *babyjub.PublicKey, batches []common.Batch) []common.Account {
  80. if totalAccounts < userAccounts {
  81. panic("totalAccounts must be greater than userAccounts")
  82. }
  83. accs := []common.Account{}
  84. for i := 0; i < totalAccounts; i++ {
  85. var addr ethCommon.Address
  86. var pubK *babyjub.PublicKey
  87. if i < userAccounts {
  88. addr = *userAddr
  89. pubK = userBjj
  90. } else {
  91. addr = ethCommon.BigToAddress(big.NewInt(int64(i)))
  92. privK := babyjub.NewRandPrivKey()
  93. pubK = privK.Public()
  94. }
  95. accs = append(accs, common.Account{
  96. Idx: common.Idx(i),
  97. TokenID: tokens[i%len(tokens)].TokenID,
  98. EthAddr: addr,
  99. BatchNum: batches[i%len(batches)].BatchNum,
  100. PublicKey: pubK,
  101. })
  102. }
  103. return accs
  104. }
  105. // GenL1Txs generates L1 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  106. func GenL1Txs(
  107. fromIdx int,
  108. totalTxs, nUserTxs int,
  109. userAddr *ethCommon.Address,
  110. accounts []common.Account,
  111. tokens []common.Token,
  112. blocks []common.Block,
  113. batches []common.Batch,
  114. ) ([]common.L1Tx, []common.L1Tx) {
  115. if totalTxs < nUserTxs {
  116. panic("totalTxs must be greater than userTxs")
  117. }
  118. userTxs := []common.L1Tx{}
  119. othersTxs := []common.L1Tx{}
  120. _, nextTxsNum := GetNextToForgeNumAndBatch(batches)
  121. for i := 0; i < totalTxs; i++ {
  122. token := tokens[i%len(tokens)]
  123. var usd *float64
  124. var lUSD *float64
  125. amount := big.NewInt(int64(i + 1))
  126. if token.USD != nil {
  127. //nolint:gomnd
  128. noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
  129. f := new(big.Float).SetInt(amount)
  130. af, _ := f.Float64()
  131. usd = new(float64)
  132. *usd = noDecimalsUSD * af
  133. lUSD = new(float64)
  134. *lUSD = noDecimalsUSD * af
  135. }
  136. tx := common.L1Tx{
  137. TxID: common.TxID(common.Hash([]byte("L1_" + strconv.Itoa(fromIdx+i)))),
  138. Position: i,
  139. UserOrigin: i%2 == 0,
  140. TokenID: token.TokenID,
  141. Amount: amount,
  142. USD: usd,
  143. LoadAmount: amount,
  144. LoadAmountUSD: lUSD,
  145. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  146. Type: randomTxType(i),
  147. }
  148. if batches[i%len(batches)].ForgeL1TxsNum != 0 {
  149. // Add already forged txs
  150. tx.BatchNum = &batches[i%len(batches)].BatchNum
  151. setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
  152. } else {
  153. // Add unforged txs
  154. tx.ToForgeL1TxsNum = nextTxsNum
  155. tx.UserOrigin = true
  156. setFromToAndAppend(tx, i, nUserTxs, userAddr, accounts, &userTxs, &othersTxs)
  157. }
  158. }
  159. return userTxs, othersTxs
  160. }
  161. // GetNextToForgeNumAndBatch returns the next BatchNum and ForgeL1TxsNum to be added
  162. func GetNextToForgeNumAndBatch(batches []common.Batch) (common.BatchNum, int64) {
  163. batchNum := batches[len(batches)-1].BatchNum + 1
  164. var toForgeL1TxsNum int64
  165. found := false
  166. for i := len(batches) - 1; i >= 0; i-- {
  167. if batches[i].ForgeL1TxsNum != 0 {
  168. toForgeL1TxsNum = batches[i].ForgeL1TxsNum + 1
  169. found = true
  170. break
  171. }
  172. }
  173. if !found {
  174. panic("toForgeL1TxsNum not found")
  175. }
  176. return batchNum, toForgeL1TxsNum
  177. }
  178. func setFromToAndAppend(
  179. tx common.L1Tx,
  180. i, nUserTxs int,
  181. userAddr *ethCommon.Address,
  182. accounts []common.Account,
  183. userTxs *[]common.L1Tx,
  184. othersTxs *[]common.L1Tx,
  185. ) {
  186. if i < nUserTxs {
  187. var from, to *common.Account
  188. var err error
  189. if i%2 == 0 {
  190. from, err = randomAccount(i, true, userAddr, accounts)
  191. if err != nil {
  192. panic(err)
  193. }
  194. to, err = randomAccount(i, false, userAddr, accounts)
  195. if err != nil {
  196. panic(err)
  197. }
  198. } else {
  199. from, err = randomAccount(i, false, userAddr, accounts)
  200. if err != nil {
  201. panic(err)
  202. }
  203. to, err = randomAccount(i, true, userAddr, accounts)
  204. if err != nil {
  205. panic(err)
  206. }
  207. }
  208. tx.FromIdx = from.Idx
  209. tx.FromEthAddr = from.EthAddr
  210. tx.FromBJJ = from.PublicKey
  211. tx.ToIdx = to.Idx
  212. *userTxs = append(*userTxs, tx)
  213. } else {
  214. from, err := randomAccount(i, false, userAddr, accounts)
  215. if err != nil {
  216. panic(err)
  217. }
  218. to, err := randomAccount(i, false, userAddr, accounts)
  219. if err != nil {
  220. panic(err)
  221. }
  222. tx.FromIdx = from.Idx
  223. tx.FromEthAddr = from.EthAddr
  224. tx.FromBJJ = from.PublicKey
  225. tx.ToIdx = to.Idx
  226. *othersTxs = append(*othersTxs, tx)
  227. }
  228. }
  229. // GenL2Txs generates L2 txs. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  230. func GenL2Txs(
  231. fromIdx int,
  232. totalTxs, nUserTxs int,
  233. userAddr *ethCommon.Address,
  234. accounts []common.Account,
  235. tokens []common.Token,
  236. blocks []common.Block,
  237. batches []common.Batch,
  238. ) ([]common.L2Tx, []common.L2Tx) {
  239. if totalTxs < nUserTxs {
  240. panic("totalTxs must be greater than userTxs")
  241. }
  242. userTxs := []common.L2Tx{}
  243. othersTxs := []common.L2Tx{}
  244. for i := 0; i < totalTxs; i++ {
  245. amount := big.NewInt(int64(i + 1))
  246. fee := common.FeeSelector(i % 256) //nolint:gomnd
  247. tx := common.L2Tx{
  248. TxID: common.TxID(common.Hash([]byte("L2_" + strconv.Itoa(fromIdx+i)))),
  249. BatchNum: batches[i%len(batches)].BatchNum,
  250. Position: i,
  251. Amount: amount,
  252. Fee: fee,
  253. Nonce: common.Nonce(i + 1),
  254. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  255. Type: randomTxType(i),
  256. }
  257. if i < nUserTxs {
  258. var from, to *common.Account
  259. var err error
  260. if i%2 == 0 {
  261. from, err = randomAccount(i, true, userAddr, accounts)
  262. if err != nil {
  263. panic(err)
  264. }
  265. to, err = randomAccount(i, false, userAddr, accounts)
  266. if err != nil {
  267. panic(err)
  268. }
  269. } else {
  270. from, err = randomAccount(i, false, userAddr, accounts)
  271. if err != nil {
  272. panic(err)
  273. }
  274. to, err = randomAccount(i, true, userAddr, accounts)
  275. if err != nil {
  276. panic(err)
  277. }
  278. }
  279. tx.FromIdx = from.Idx
  280. tx.ToIdx = to.Idx
  281. } else {
  282. from, err := randomAccount(i, false, userAddr, accounts)
  283. if err != nil {
  284. panic(err)
  285. }
  286. to, err := randomAccount(i, false, userAddr, accounts)
  287. if err != nil {
  288. panic(err)
  289. }
  290. tx.FromIdx = from.Idx
  291. tx.ToIdx = to.Idx
  292. }
  293. var usd *float64
  294. var fUSD *float64
  295. token := GetToken(tx.FromIdx, accounts, tokens)
  296. if token.USD != nil {
  297. //nolint:gomnd
  298. noDecimalsUSD := *token.USD / math.Pow(10, float64(token.Decimals))
  299. f := new(big.Float).SetInt(amount)
  300. af, _ := f.Float64()
  301. usd = new(float64)
  302. fUSD = new(float64)
  303. *usd = noDecimalsUSD * af
  304. *fUSD = *usd * fee.Percentage()
  305. }
  306. tx.USD = usd
  307. tx.FeeUSD = fUSD
  308. if i < nUserTxs {
  309. userTxs = append(userTxs, tx)
  310. } else {
  311. othersTxs = append(othersTxs, tx)
  312. }
  313. }
  314. return userTxs, othersTxs
  315. }
  316. // GetToken returns the Token associated to an Idx given a list of tokens and accounts.
  317. // It panics when not found, intended for testing only.
  318. func GetToken(idx common.Idx, accs []common.Account, tokens []common.Token) common.Token {
  319. var id common.TokenID
  320. found := false
  321. for _, acc := range accs {
  322. if acc.Idx == idx {
  323. found = true
  324. id = acc.TokenID
  325. break
  326. }
  327. }
  328. if !found {
  329. panic("tokenID not found")
  330. }
  331. for i := 0; i < len(tokens); i++ {
  332. if tokens[i].TokenID == id {
  333. return tokens[i]
  334. }
  335. }
  336. panic("token not found")
  337. }
  338. // GenCoordinators generates coordinators. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  339. func GenCoordinators(nCoords int, blocks []common.Block) []common.Coordinator {
  340. coords := []common.Coordinator{}
  341. for i := 0; i < nCoords; i++ {
  342. coords = append(coords, common.Coordinator{
  343. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  344. Forger: ethCommon.BigToAddress(big.NewInt(int64(i))),
  345. WithdrawAddr: ethCommon.BigToAddress(big.NewInt(int64(i))),
  346. URL: "https://foo.bar",
  347. })
  348. }
  349. return coords
  350. }
  351. // GenBids generates bids. WARNING: This is meant for DB/API testing, and may not be fully consistent with the protocol.
  352. func GenBids(nBids int, blocks []common.Block, coords []common.Coordinator) []common.Bid {
  353. bids := []common.Bid{}
  354. for i := 0; i < nBids; i++ {
  355. bids = append(bids, common.Bid{
  356. SlotNum: common.SlotNum(i),
  357. BidValue: big.NewInt(int64(i)),
  358. EthBlockNum: blocks[i%len(blocks)].EthBlockNum,
  359. ForgerAddr: coords[i%len(blocks)].Forger,
  360. })
  361. }
  362. return bids
  363. }
  364. // GenExitTree generates an exitTree (as an array of Exits)
  365. //nolint:gomnd
  366. func GenExitTree(n int) []common.ExitInfo {
  367. exitTree := make([]common.ExitInfo, n)
  368. for i := 0; i < n; i++ {
  369. exitTree[i] = common.ExitInfo{
  370. BatchNum: common.BatchNum(i + 1),
  371. InstantWithdrawn: nil,
  372. DelayedWithdrawRequest: nil,
  373. DelayedWithdrawn: nil,
  374. AccountIdx: common.Idx(i * 10),
  375. MerkleProof: &merkletree.CircomVerifierProof{
  376. Root: &merkletree.Hash{byte(i), byte(i + 1)},
  377. Siblings: []*big.Int{
  378. big.NewInt(int64(i) * 10),
  379. big.NewInt(int64(i)*100 + 1),
  380. big.NewInt(int64(i)*1000 + 2)},
  381. OldKey: &merkletree.Hash{byte(i * 1), byte(i*1 + 1)},
  382. OldValue: &merkletree.Hash{byte(i * 2), byte(i*2 + 1)},
  383. IsOld0: i%2 == 0,
  384. Key: &merkletree.Hash{byte(i * 3), byte(i*3 + 1)},
  385. Value: &merkletree.Hash{byte(i * 4), byte(i*4 + 1)},
  386. Fnc: i % 2,
  387. },
  388. Balance: big.NewInt(int64(i) * 1000),
  389. }
  390. }
  391. return exitTree
  392. }
  393. func randomAccount(seed int, userAccount bool, userAddr *ethCommon.Address, accs []common.Account) (*common.Account, error) {
  394. i := seed % len(accs)
  395. firstI := i
  396. for {
  397. acc := accs[i]
  398. if userAccount && *userAddr == acc.EthAddr {
  399. return &acc, nil
  400. }
  401. if !userAccount && (userAddr == nil || *userAddr != acc.EthAddr) {
  402. return &acc, nil
  403. }
  404. i++
  405. i = i % len(accs)
  406. if i == firstI {
  407. return &acc, errors.New("Didnt found any account matchinng the criteria")
  408. }
  409. }
  410. }
  411. func randomTxType(seed int) common.TxType {
  412. //nolint:gomnd
  413. switch seed % 11 {
  414. case 0:
  415. return common.TxTypeExit
  416. //nolint:gomnd
  417. case 1:
  418. return common.TxTypeWithdrawn
  419. //nolint:gomnd
  420. case 2:
  421. return common.TxTypeTransfer
  422. //nolint:gomnd
  423. case 3:
  424. return common.TxTypeDeposit
  425. //nolint:gomnd
  426. case 4:
  427. return common.TxTypeCreateAccountDeposit
  428. //nolint:gomnd
  429. case 5:
  430. return common.TxTypeCreateAccountDepositTransfer
  431. //nolint:gomnd
  432. case 6:
  433. return common.TxTypeDepositTransfer
  434. //nolint:gomnd
  435. case 7:
  436. return common.TxTypeForceTransfer
  437. //nolint:gomnd
  438. case 8:
  439. return common.TxTypeForceExit
  440. //nolint:gomnd
  441. case 9:
  442. return common.TxTypeTransferToEthAddr
  443. //nolint:gomnd
  444. case 10:
  445. return common.TxTypeTransferToBJJ
  446. default:
  447. return common.TxTypeTransfer
  448. }
  449. }