From 60fa76b4d2925667ef666823918acd1b900a9cb6 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Thu, 13 Aug 2020 10:51:04 +0200 Subject: [PATCH] Integrate TxSelector with StateDB --- README.md | 11 +++ batchbuilder/batchbuilder_test.go | 4 +- common/pooll2tx.go | 1 + db/statedb/statedb.go | 8 +- txselector/common/tmp.go | 40 -------- txselector/mock/mock.go | 33 ------- txselector/txselector.go | 155 +++++++++++++++++------------- txselector/txselector_test.go | 126 ++++++++++++------------ txselector/utils.go | 16 --- 9 files changed, 175 insertions(+), 219 deletions(-) delete mode 100644 txselector/common/tmp.go delete mode 100644 txselector/mock/mock.go delete mode 100644 txselector/utils.go diff --git a/README.md b/README.md index e0017af..65aa721 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ # hermez-node [![Go Report Card](https://goreportcard.com/badge/github.com/hermeznetwork/hermez-node)](https://goreportcard.com/report/github.com/hermeznetwork/hermez-node) [![Test Status](https://github.com/hermeznetwork/hermez-node/workflows/Test/badge.svg)](https://github.com/hermeznetwork/hermez-node/actions?query=workflow%3ATest) [![Lint Status](https://github.com/hermeznetwork/hermez-node/workflows/Lint/badge.svg)](https://github.com/hermeznetwork/hermez-node/actions?query=workflow%3ALint) [![GoDoc](https://godoc.org/github.com/hermeznetwork/hermez-node?status.svg)](https://godoc.org/github.com/hermeznetwork/hermez-node) Go implementation of the Hermez node. + + +## Test +- First run a docker instance of the PostgresSQL (where `yourpasswordhere` should be your password) +``` +POSTGRES_PASS=yourpasswordhere; sudo docker run --rm --name hermez-db-test -p 5432:5432 -e POSTGRES_DB=history -e POSTGRES_USER=hermez -e POSTGRES_PASSWORD="$POSTGRES_PASS" -d postgres && sleep 2s && sudo docker exec hermez-db-test psql -a history -U hermez -c "CREATE DATABASE l2;" +``` +- Then, run the tests with the password as env var +``` +POSTGRES_PASS=yourpasswordhere go test ./... +``` diff --git a/batchbuilder/batchbuilder_test.go b/batchbuilder/batchbuilder_test.go index 6dfb18b..696c847 100644 --- a/batchbuilder/batchbuilder_test.go +++ b/batchbuilder/batchbuilder_test.go @@ -14,10 +14,10 @@ func TestBatchBuilder(t *testing.T) { dir, err := ioutil.TempDir("", "tmpdb") require.Nil(t, err) - sdb, err := statedb.NewStateDB(dir, false, false, 0) + synchDB, err := statedb.NewStateDB(dir, false, false, 0) assert.Nil(t, err) - bb, err := NewBatchBuilder(sdb, nil, 0, 0, 32) + bb, err := NewBatchBuilder(synchDB, nil, 0, 0, 32) assert.Nil(t, err) fmt.Println(bb) } diff --git a/common/pooll2tx.go b/common/pooll2tx.go index 28671c9..fb943ed 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -18,6 +18,7 @@ type PoolL2Tx struct { Timestamp time.Time // time when added to the tx pool Signature babyjub.Signature // tx signature ToEthAddr eth.Address + AbsoluteFee float64 // TODO add methods to calculate this value from Tx.Fee tables + priceupdater tables } // RqTx Transaction Data used to indicate that a transaction depends on another transaction diff --git a/db/statedb/statedb.go b/db/statedb/statedb.go index 1718bf7..3525b53 100644 --- a/db/statedb/statedb.go +++ b/db/statedb/statedb.go @@ -210,6 +210,12 @@ func NewLocalStateDB(synchronizerDB *StateDB, withMT bool, nLevels int) (*LocalS // LocalStateDB.synchronizerStateDB for the given batchNum func (l *LocalStateDB) Reset(batchNum int, fromSynchronizer bool) error { // TODO - + // if fromSynchronizer==true: + // make copy from l.synchronizerStateDB at the batchNum to the localStateDB + // if synchronizerStateDB does not have batchNum, return err + // the localStateDB checkpoint is set to batchNum + // else fromSynchronizer==false: + // the localStateDB checkpoint is set to batchNum + // if localStateDB does not have batchNum, return err return nil } diff --git a/txselector/common/tmp.go b/txselector/common/tmp.go deleted file mode 100644 index d41712b..0000000 --- a/txselector/common/tmp.go +++ /dev/null @@ -1,40 +0,0 @@ -package common - -import ( - "math/big" - - ethCommon "github.com/ethereum/go-ethereum/common" -) - -// WIP this will be from hermeznetwork/common -type Tx struct { - FromAx [32]byte - FromAy [32]byte - FromEthAddr ethCommon.Address - ToAx [32]byte - ToAy [32]byte - ToEthAddr ethCommon.Address - OnChain bool - RqOffset []byte - NewAccount bool - TokenID uint32 - LoadAmount [3]byte - Amount [3]byte - Nonce uint64 - UserFee uint8 - UserFeeAbsolute uint64 - R8x [32]byte - R8y [32]byte - S [32]byte - RqTxData [32]byte -} - -// WIP this will be from hermeznetwork/common -type Account struct { - EthAddr ethCommon.Address - TokenID uint32 - Idx uint32 - Nonce uint64 - Balance *big.Int - // Ax, Ay -} diff --git a/txselector/mock/mock.go b/txselector/mock/mock.go deleted file mode 100644 index 3ceeeca..0000000 --- a/txselector/mock/mock.go +++ /dev/null @@ -1,33 +0,0 @@ -package mock - -import ( - "github.com/hermeznetwork/hermez-node/txselector/common" -) - -type MockDB struct { - Txs map[uint64][]common.Tx - - // AccountDB is the LocalAccountDB copy of the original AccountDB - AccountDB map[[36]byte]common.Account // [36]byte is tx.ToEthAddr + tx.TokenID - - PendingRegistersDB map[[36]byte]common.Account // [36]byte is tx.ToEthAddr + tx.TokenID -} - -func New() *MockDB { - return &MockDB{ - Txs: make(map[uint64][]common.Tx), - AccountDB: make(map[[36]byte]common.Account), - PendingRegistersDB: make(map[[36]byte]common.Account), - } -} - -func (m *MockDB) AddTx(batchID uint64, tx common.Tx) { - if _, ok := m.Txs[batchID]; !ok { - m.Txs[batchID] = []common.Tx{} - } - m.Txs[batchID] = append(m.Txs[batchID], tx) -} - -func (m *MockDB) GetTxs(batchID uint64) []common.Tx { - return m.Txs[batchID] -} diff --git a/txselector/txselector.go b/txselector/txselector.go index f07f987..fed9ad8 100644 --- a/txselector/txselector.go +++ b/txselector/txselector.go @@ -3,12 +3,13 @@ package txselector import ( "sort" - "github.com/hermeznetwork/hermez-node/txselector/common" - "github.com/hermeznetwork/hermez-node/txselector/mock" + "github.com/hermeznetwork/hermez-node/common" + "github.com/hermeznetwork/hermez-node/db/l2db" + "github.com/hermeznetwork/hermez-node/db/statedb" ) // txs implements the interface Sort for an array of Tx -type txs []common.Tx +type txs []common.PoolL2Tx func (t txs) Len() int { return len(t) @@ -17,57 +18,68 @@ func (t txs) Swap(i, j int) { t[i], t[j] = t[j], t[i] } func (t txs) Less(i, j int) bool { - return t[i].UserFeeAbsolute > t[j].UserFeeAbsolute + return t[i].AbsoluteFee > t[j].AbsoluteFee } +// TxSelector implements all the functionalities to select the txs for the next batch type TxSelector struct { - // NMax is the maximum L1-user-tx for a batch - NMax uint64 - // MMax is the maximum L1-operator-tx for a batch - MMax uint64 - // PMax is the maximum L2-tx for a batch - PMax uint64 - // DB is a pointer to the database interface - DB *mock.MockDB + // MaxL1UserTxs is the maximum L1-user-tx for a batch + MaxL1UserTxs uint64 + // MaxL1OperatorTxs is the maximum L1-operator-tx for a batch + MaxL1OperatorTxs uint64 + // MaxTxs is the maximum txs for a batch + MaxTxs uint64 + + l2db *l2db.L2DB + localAccountsDB *statedb.LocalStateDB } -func NewTxSelector(db *mock.MockDB, nMax, mMax, pMax uint64) *TxSelector { - return &TxSelector{ - NMax: nMax, - MMax: mMax, - PMax: pMax, - DB: db, +// NewTxSelector returns a *TxSelector +func NewTxSelector(synchronizerStateDB *statedb.StateDB, l2 *l2db.L2DB, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) (*TxSelector, error) { + localAccountsDB, err := statedb.NewLocalStateDB(synchronizerStateDB, false, 0) // without merkletree + if err != nil { + return nil, err } -} -func (txsel *TxSelector) updateLocalAccountDB(batchId uint64) error { - // if batchID > max(localAccountDB.BatchID) + 1 - // make a checkpoint of AccountDB at BatchID to a localAccountDB - // use localAccountDB[inputBatchID-1] + return &TxSelector{ + MaxL1UserTxs: maxL1UserTxs, + MaxL1OperatorTxs: maxL1OperatorTxs, + MaxTxs: maxTxs, + l2db: l2, + localAccountsDB: localAccountsDB, + }, nil +} +// Reset tells the TxSelector to get it's internal AccountsDB +// from the required `batchNum` +func (txsel *TxSelector) Reset(batchNum int) error { + err := txsel.localAccountsDB.Reset(batchNum, true) + if err != nil { + return err + } return nil } -func (txsel *TxSelector) GetL2TxSelection(batchID uint64) ([]common.Tx, error) { - err := txsel.updateLocalAccountDB(batchID) +// GetL2TxSelection returns a selection of the L2Txs for the next batch, from the L2DB pool +func (txsel *TxSelector) GetL2TxSelection(batchNum int) ([]common.PoolL2Tx, error) { + // get pending l2-tx from tx-pool + l2TxsRaw, err := txsel.l2db.GetPendingTxs() // once l2db ready, maybe use parameter 'batchNum' if err != nil { return nil, err } - // get pending l2-tx from tx-pool - txsRaw := txsel.DB.GetTxs(batchID) - // discard the txs that don't have an Account in the AccountDB var validTxs txs - for _, tx := range txsRaw { - accountID := getAccountID(tx.ToEthAddr, tx.TokenID) - if _, ok := txsel.DB.AccountDB[accountID]; ok { + for _, tx := range l2TxsRaw { + _, err = txsel.localAccountsDB.GetAccount(tx.FromIdx) + if err == nil { + // if FromIdx has an account into the AccountsDB validTxs = append(validTxs, tx) } } - // get most profitable L2-tx (len