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.

330 lines
9.2 KiB

  1. package statedb
  2. import (
  3. "math/big"
  4. "github.com/hermeznetwork/hermez-node/common"
  5. "github.com/iden3/go-iden3-crypto/poseidon"
  6. "github.com/iden3/go-merkletree"
  7. "github.com/iden3/go-merkletree/db"
  8. "github.com/iden3/go-merkletree/db/memory"
  9. )
  10. // keyidx is used as key in the db to store the current Idx
  11. var keyidx = []byte("idx")
  12. // ProcessTxs process the given L1Txs & L2Txs applying the needed updates to
  13. // the StateDB depending on the transaction Type. Returns the common.ZKInputs
  14. // to generate the SnarkProof later used by the BatchBuilder, and if
  15. // cmpExitTree is set to true, returns common.ExitTreeLeaf that is later used
  16. // by the Synchronizer to update the HistoryDB.
  17. func (s *StateDB) ProcessTxs(cmpExitTree bool, l1usertxs, l1coordinatortxs []*common.L1Tx, l2txs []*common.L2Tx) (*common.ZKInputs, []*common.ExitInfo, error) {
  18. var err error
  19. var exitTree *merkletree.MerkleTree
  20. exits := make(map[common.Idx]common.Account)
  21. // TBD if ExitTree is only in memory or stored in disk, for the moment
  22. // only needed in memory
  23. exitTree, err = merkletree.NewMerkleTree(memory.NewMemoryStorage(), s.mt.MaxLevels())
  24. if err != nil {
  25. return nil, nil, err
  26. }
  27. for _, tx := range l1coordinatortxs {
  28. exitIdx, exitAccount, err := s.processL1Tx(exitTree, tx)
  29. if err != nil {
  30. return nil, nil, err
  31. }
  32. if exitIdx != nil && cmpExitTree {
  33. exits[*exitIdx] = *exitAccount
  34. }
  35. }
  36. for _, tx := range l1usertxs {
  37. exitIdx, exitAccount, err := s.processL1Tx(exitTree, tx)
  38. if err != nil {
  39. return nil, nil, err
  40. }
  41. if exitIdx != nil && cmpExitTree {
  42. exits[*exitIdx] = *exitAccount
  43. }
  44. }
  45. for _, tx := range l2txs {
  46. exitIdx, exitAccount, err := s.processL2Tx(exitTree, tx)
  47. if err != nil {
  48. return nil, nil, err
  49. }
  50. if exitIdx != nil && cmpExitTree {
  51. exits[*exitIdx] = *exitAccount
  52. }
  53. }
  54. if !cmpExitTree {
  55. return nil, nil, nil
  56. }
  57. // once all txs processed (exitTree root frozen), for each leaf
  58. // generate common.ExitInfo data
  59. var exitInfos []*common.ExitInfo
  60. for exitIdx, exitAccount := range exits {
  61. // 0. generate MerkleProof
  62. p, err := exitTree.GenerateCircomVerifierProof(exitIdx.BigInt(), nil)
  63. if err != nil {
  64. return nil, nil, err
  65. }
  66. // 1. compute nullifier
  67. exitAccStateValue, err := exitAccount.HashValue()
  68. if err != nil {
  69. return nil, nil, err
  70. }
  71. nullifier, err := poseidon.Hash([]*big.Int{
  72. exitAccStateValue,
  73. big.NewInt(int64(s.currentBatch)),
  74. exitTree.Root().BigInt(),
  75. })
  76. if err != nil {
  77. return nil, nil, err
  78. }
  79. // 2. generate common.ExitInfo
  80. ei := &common.ExitInfo{
  81. AccountIdx: exitIdx,
  82. MerkleProof: p,
  83. Nullifier: nullifier,
  84. Balance: exitAccount.Balance,
  85. }
  86. exitInfos = append(exitInfos, ei)
  87. }
  88. // return exitInfos, so Synchronizer will be able to store it into
  89. // HistoryDB for the concrete BatchNum
  90. return nil, exitInfos, nil
  91. }
  92. // processL1Tx process the given L1Tx applying the needed updates to the
  93. // StateDB depending on the transaction Type.
  94. func (s *StateDB) processL1Tx(exitTree *merkletree.MerkleTree, tx *common.L1Tx) (*common.Idx, *common.Account, error) {
  95. switch tx.Type {
  96. case common.TxTypeForceTransfer, common.TxTypeTransfer:
  97. // go to the MT account of sender and receiver, and update balance
  98. // & nonce
  99. err := s.applyTransfer(tx.Tx())
  100. if err != nil {
  101. return nil, nil, err
  102. }
  103. case common.TxTypeCreateAccountDeposit:
  104. // add new account to the MT, update balance of the MT account
  105. err := s.applyCreateAccount(tx)
  106. if err != nil {
  107. return nil, nil, err
  108. }
  109. case common.TxTypeDeposit:
  110. // update balance of the MT account
  111. err := s.applyDeposit(tx, false)
  112. if err != nil {
  113. return nil, nil, err
  114. }
  115. case common.TxTypeDepositTransfer:
  116. // update balance in MT account, update balance & nonce of sender
  117. // & receiver
  118. err := s.applyDeposit(tx, true)
  119. if err != nil {
  120. return nil, nil, err
  121. }
  122. case common.TxTypeCreateAccountDepositTransfer:
  123. // add new account to the merkletree, update balance in MT account,
  124. // update balance & nonce of sender & receiver
  125. err := s.applyCreateAccount(tx)
  126. if err != nil {
  127. return nil, nil, err
  128. }
  129. err = s.applyTransfer(tx.Tx())
  130. if err != nil {
  131. return nil, nil, err
  132. }
  133. case common.TxTypeExit:
  134. // execute exit flow
  135. exitAccount, err := s.applyExit(exitTree, tx.Tx())
  136. if err != nil {
  137. return nil, nil, err
  138. }
  139. return &tx.FromIdx, exitAccount, nil
  140. default:
  141. }
  142. return nil, nil, nil
  143. }
  144. // processL2Tx process the given L2Tx applying the needed updates to
  145. // the StateDB depending on the transaction Type.
  146. func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.L2Tx) (*common.Idx, *common.Account, error) {
  147. switch tx.Type {
  148. case common.TxTypeTransfer:
  149. // go to the MT account of sender and receiver, and update
  150. // balance & nonce
  151. err := s.applyTransfer(tx.Tx())
  152. if err != nil {
  153. return nil, nil, err
  154. }
  155. case common.TxTypeExit:
  156. // execute exit flow
  157. exitAccount, err := s.applyExit(exitTree, tx.Tx())
  158. if err != nil {
  159. return nil, nil, err
  160. }
  161. return &tx.FromIdx, exitAccount, nil
  162. default:
  163. }
  164. return nil, nil, nil
  165. }
  166. // applyCreateAccount creates a new account in the account of the depositer, it
  167. // stores the deposit value
  168. func (s *StateDB) applyCreateAccount(tx *common.L1Tx) error {
  169. account := &common.Account{
  170. TokenID: tx.TokenID,
  171. Nonce: 0,
  172. Balance: tx.LoadAmount,
  173. PublicKey: tx.FromBJJ,
  174. EthAddr: tx.FromEthAddr,
  175. }
  176. _, err := s.CreateAccount(common.Idx(s.idx+1), account)
  177. if err != nil {
  178. return err
  179. }
  180. s.idx = s.idx + 1
  181. return s.setIdx(s.idx)
  182. }
  183. // applyDeposit updates the balance in the account of the depositer, if
  184. // andTransfer parameter is set to true, the method will also apply the
  185. // Transfer of the L1Tx/DepositTransfer
  186. func (s *StateDB) applyDeposit(tx *common.L1Tx, transfer bool) error {
  187. // deposit the tx.LoadAmount into the sender account
  188. accSender, err := s.GetAccount(tx.FromIdx)
  189. if err != nil {
  190. return err
  191. }
  192. accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
  193. // in case that the tx is a L1Tx>DepositTransfer
  194. if transfer {
  195. accReceiver, err := s.GetAccount(tx.ToIdx)
  196. if err != nil {
  197. return err
  198. }
  199. // subtract amount to the sender
  200. accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
  201. // add amount to the receiver
  202. accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
  203. // update receiver account in localStateDB
  204. _, err = s.UpdateAccount(tx.ToIdx, accReceiver)
  205. if err != nil {
  206. return err
  207. }
  208. }
  209. // update sender account in localStateDB
  210. _, err = s.UpdateAccount(tx.FromIdx, accSender)
  211. if err != nil {
  212. return err
  213. }
  214. return nil
  215. }
  216. // applyTransfer updates the balance & nonce in the account of the sender, and
  217. // the balance in the account of the receiver
  218. func (s *StateDB) applyTransfer(tx *common.Tx) error {
  219. // get sender and receiver accounts from localStateDB
  220. accSender, err := s.GetAccount(tx.FromIdx)
  221. if err != nil {
  222. return err
  223. }
  224. accReceiver, err := s.GetAccount(tx.ToIdx)
  225. if err != nil {
  226. return err
  227. }
  228. // increment nonce
  229. accSender.Nonce++
  230. // subtract amount to the sender
  231. accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
  232. // add amount to the receiver
  233. accReceiver.Balance = new(big.Int).Add(accReceiver.Balance, tx.Amount)
  234. // update receiver account in localStateDB
  235. _, err = s.UpdateAccount(tx.ToIdx, accReceiver)
  236. if err != nil {
  237. return err
  238. }
  239. // update sender account in localStateDB
  240. _, err = s.UpdateAccount(tx.FromIdx, accSender)
  241. if err != nil {
  242. return err
  243. }
  244. return nil
  245. }
  246. func (s *StateDB) applyExit(exitTree *merkletree.MerkleTree, tx *common.Tx) (*common.Account, error) {
  247. // 0. subtract tx.Amount from current Account in StateMT
  248. // add the tx.Amount into the Account (tx.FromIdx) in the ExitMT
  249. acc, err := s.GetAccount(tx.FromIdx)
  250. if err != nil {
  251. return nil, err
  252. }
  253. acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
  254. _, err = s.UpdateAccount(tx.FromIdx, acc)
  255. if err != nil {
  256. return nil, err
  257. }
  258. exitAccount, err := getAccountInTreeDB(exitTree.DB(), tx.FromIdx)
  259. if err == db.ErrNotFound {
  260. // 1a. if idx does not exist in exitTree:
  261. // add new leaf 'ExitTreeLeaf', where ExitTreeLeaf.Balance = exitAmount (exitAmount=tx.Amount)
  262. exitAccount := &common.Account{
  263. TokenID: acc.TokenID,
  264. Nonce: common.Nonce(1),
  265. Balance: tx.Amount,
  266. PublicKey: acc.PublicKey,
  267. EthAddr: acc.EthAddr,
  268. }
  269. _, err = createAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
  270. return exitAccount, err
  271. } else if err != nil {
  272. return exitAccount, err
  273. }
  274. // 1b. if idx already exist in exitTree:
  275. // update account, where account.Balance += exitAmount
  276. exitAccount.Balance = new(big.Int).Add(exitAccount.Balance, tx.Amount)
  277. _, err = updateAccountInTreeDB(exitTree.DB(), exitTree, tx.FromIdx, exitAccount)
  278. return exitAccount, err
  279. }
  280. // getIdx returns the stored Idx from the localStateDB, which is the last Idx
  281. // used for an Account in the localStateDB.
  282. func (s *StateDB) getIdx() (common.Idx, error) {
  283. idxBytes, err := s.DB().Get(keyidx)
  284. if err == db.ErrNotFound {
  285. return 0, nil
  286. }
  287. if err != nil {
  288. return 0, err
  289. }
  290. return common.IdxFromBytes(idxBytes[:4])
  291. }
  292. // setIdx stores Idx in the localStateDB
  293. func (s *StateDB) setIdx(idx common.Idx) error {
  294. tx, err := s.DB().NewTx()
  295. if err != nil {
  296. return err
  297. }
  298. tx.Put(keyidx, idx.Bytes())
  299. if err := tx.Commit(); err != nil {
  300. return err
  301. }
  302. return nil
  303. }