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.

142 lines
3.7 KiB

  1. package txselector
  2. import (
  3. "sort"
  4. "github.com/hermeznetwork/hermez-node/tx-selector/common"
  5. "github.com/hermeznetwork/hermez-node/tx-selector/mock"
  6. )
  7. // txs implements the interface Sort for an array of Tx
  8. type txs []common.Tx
  9. func (t txs) Len() int {
  10. return len(t)
  11. }
  12. func (t txs) Swap(i, j int) {
  13. t[i], t[j] = t[j], t[i]
  14. }
  15. func (t txs) Less(i, j int) bool {
  16. return t[i].UserFeeAbsolute > t[j].UserFeeAbsolute
  17. }
  18. type TxSelector struct {
  19. // NMax is the maximum L1-user-tx for a batch
  20. NMax uint64
  21. // MMax is the maximum L1-operator-tx for a batch
  22. MMax uint64
  23. // PMax is the maximum L2-tx for a batch
  24. PMax uint64
  25. // DB is a pointer to the database interface
  26. DB *mock.MockDB
  27. }
  28. func NewTxSelector(db *mock.MockDB, nMax, mMax, pMax uint64) *TxSelector {
  29. return &TxSelector{
  30. NMax: nMax,
  31. MMax: mMax,
  32. PMax: pMax,
  33. DB: db,
  34. }
  35. }
  36. func (txsel *TxSelector) updateLocalAccountDB(batchId uint64) error {
  37. // if batchID > max(localAccountDB.BatchID) + 1
  38. // make a checkpoint of AccountDB at BatchID to a localAccountDB
  39. // use localAccountDB[inputBatchID-1]
  40. return nil
  41. }
  42. func (txsel *TxSelector) GetL2TxSelection(batchID uint64) ([]common.Tx, error) {
  43. err := txsel.updateLocalAccountDB(batchID)
  44. if err != nil {
  45. return nil, err
  46. }
  47. // get pending l2-tx from tx-pool
  48. txsRaw := txsel.DB.GetTxs(batchID)
  49. // discard the txs that don't have an Account in the AccountDB
  50. var validTxs txs
  51. for _, tx := range txsRaw {
  52. accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
  53. if _, ok := txsel.DB.AccountDB[accountID]; ok {
  54. validTxs = append(validTxs, tx)
  55. }
  56. }
  57. // get most profitable L2-tx (len<NMax)
  58. txs := txsel.getL2Profitable(validTxs)
  59. // apply L2-tx to local AccountDB, make checkpoint tagged with BatchID
  60. // update balances
  61. // update nonces
  62. // return selected txs
  63. return txs, nil
  64. }
  65. func (txsel *TxSelector) GetL1L2TxSelection(batchID uint64, l1txs []common.Tx) ([]common.Tx, []common.Tx, []common.Tx, error) {
  66. err := txsel.updateLocalAccountDB(batchID)
  67. if err != nil {
  68. return nil, nil, nil, err
  69. }
  70. // apply l1-user-tx to localAccountDB
  71. // create new leaves
  72. // update balances
  73. // update nonces
  74. // get pending l2-tx from tx-pool
  75. txsRaw := txsel.DB.GetTxs(batchID)
  76. // discard the txs that don't have an Account in the AccountDB
  77. // neither appear in the PendingRegistersDB
  78. var validTxs txs
  79. for _, tx := range txsRaw {
  80. accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
  81. exist := txsel.checkIfAccountExist(accountID)
  82. if exist {
  83. validTxs = append(validTxs, tx)
  84. }
  85. }
  86. // get most profitable L2-tx (len<NMax)
  87. l2txs := txsel.getL2Profitable(validTxs)
  88. // prepare (from the selected l2txs) pending to register from the PendingRegistersDB
  89. var pendingRegisters []common.Account
  90. for _, tx := range l2txs {
  91. accountID := getAccountID(tx.ToEthAddr, tx.TokenID)
  92. if toRegister, ok := txsel.DB.PendingRegistersDB[accountID]; ok {
  93. pendingRegisters = append(pendingRegisters, toRegister)
  94. }
  95. }
  96. // create L1-operator-tx for each L2-tx selected in which the recipient does not have account
  97. l1OperatorTxs := txsel.createL1OperatorTxForL2Tx(pendingRegisters) // only with the L2-tx selected ones
  98. return l1txs, l2txs, l1OperatorTxs, nil
  99. }
  100. func (txsel *TxSelector) checkIfAccountExist(accountID [36]byte) bool {
  101. // check if account exist in AccountDB
  102. if _, ok := txsel.DB.AccountDB[accountID]; ok {
  103. return true
  104. }
  105. // check if account is pending to register
  106. if _, ok := txsel.DB.PendingRegistersDB[accountID]; ok {
  107. return true
  108. }
  109. return false
  110. }
  111. func (txsel *TxSelector) getL2Profitable(txs txs) txs {
  112. sort.Sort(txs)
  113. return txs[:txsel.PMax]
  114. }
  115. func (txsel *TxSelector) createL1OperatorTxForL2Tx(accounts []common.Account) txs {
  116. //
  117. return txs{}
  118. }