diff --git a/common/pooll2tx.go b/common/pooll2tx.go index 377a214..9600f83 100644 --- a/common/pooll2tx.go +++ b/common/pooll2tx.go @@ -22,7 +22,7 @@ type PoolL2Tx struct { FromIdx Idx `meddler:"from_idx"` ToIdx Idx `meddler:"to_idx,zeroisnull"` AuxToIdx Idx `meddler:"-"` // AuxToIdx is only used internally at the StateDB to avoid repeated computation when processing transactions (from Synchronizer, TxSelector, BatchBuilder) - ToEthAddr ethCommon.Address `meddler:"to_eth_addr"` + ToEthAddr ethCommon.Address `meddler:"to_eth_addr,zeroisnull"` ToBJJ *babyjub.PublicKey `meddler:"to_bjj"` TokenID TokenID `meddler:"token_id"` Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16 @@ -34,7 +34,7 @@ type PoolL2Tx struct { // Stored in DB: optional fileds, may be uninitialized RqFromIdx Idx `meddler:"rq_from_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit) RqToIdx Idx `meddler:"rq_to_idx,zeroisnull"` // FromIdx is used by L1Tx/Deposit to indicate the Idx receiver of the L1Tx.LoadAmount (deposit) - RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr"` + RqToEthAddr ethCommon.Address `meddler:"rq_to_eth_addr,zeroisnull"` RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"` // TODO: stop using json, use scanner/valuer RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"` RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16 diff --git a/coordinator/coordinator.go b/coordinator/coordinator.go index 0bf2c9f..ac5221f 100644 --- a/coordinator/coordinator.go +++ b/coordinator/coordinator.go @@ -220,7 +220,7 @@ func (c *Coordinator) forge(serverProof ServerProofInterface) (*BatchInfo, error } } else { // 2b: only L2 txs - poolL2Txs, err = c.txsel.GetL2TxSelection([]common.Idx{}, c.batchNum) // TODO once feesInfo is added to method return, add the var + _, poolL2Txs, err = c.txsel.GetL2TxSelection([]common.Idx{}, c.batchNum) // TODO once feesInfo is added to method return, add the var if err != nil { return nil, err } diff --git a/db/l2db/l2db.go b/db/l2db/l2db.go index fdfc9a5..252e06d 100644 --- a/db/l2db/l2db.go +++ b/db/l2db/l2db.go @@ -82,7 +82,7 @@ func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error { Amount: tx.Amount, Fee: tx.Fee, Nonce: tx.Nonce, - State: tx.State, + State: common.PoolL2TxStatePending, Signature: tx.Signature, RqToBJJ: tx.RqToBJJ, RqAmount: tx.RqAmount, diff --git a/test/til/txs.go b/test/til/txs.go index 1389b98..c6c1277 100644 --- a/test/til/txs.go +++ b/test/til/txs.go @@ -30,7 +30,7 @@ type Context struct { Instructions []instruction userNames []string Users map[string]*User - lastRegisteredTokenID common.TokenID + LastRegisteredTokenID common.TokenID l1CreatedAccounts map[string]*Account // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch @@ -56,7 +56,7 @@ func NewContext(rollupConstMaxL1UserTx int) *Context { return &Context{ Users: make(map[string]*User), l1CreatedAccounts: make(map[string]*Account), - lastRegisteredTokenID: 0, + LastRegisteredTokenID: 0, rollupConstMaxL1UserTx: rollupConstMaxL1UserTx, idx: common.UserThreshold, @@ -323,10 +323,10 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) { TokenID: inst.tokenID, EthBlockNum: tc.blockNum, } - if inst.tokenID != tc.lastRegisteredTokenID+1 { - return nil, fmt.Errorf("Line %d: AddToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", inst.lineNum, tc.lastRegisteredTokenID+1, inst.tokenID) + if inst.tokenID != tc.LastRegisteredTokenID+1 { + return nil, fmt.Errorf("Line %d: AddToken TokenID should be sequential, expected TokenID: %d, defined TokenID: %d", inst.lineNum, tc.LastRegisteredTokenID+1, inst.tokenID) } - tc.lastRegisteredTokenID++ + tc.LastRegisteredTokenID++ tc.currBlock.AddedTokens = append(tc.currBlock.AddedTokens, newToken) default: return nil, fmt.Errorf("Line %d: Unexpected type: %s", inst.lineNum, inst.typ) @@ -457,8 +457,8 @@ func (tc *Context) checkIfAccountExists(tf string, inst instruction) error { return nil } func (tc *Context) checkIfTokenIsRegistered(inst instruction) error { - if inst.tokenID > tc.lastRegisteredTokenID { - return fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.lastRegisteredTokenID) + if inst.tokenID > tc.LastRegisteredTokenID { + return fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.LastRegisteredTokenID) } return nil } diff --git a/txselector/txselector.go b/txselector/txselector.go index f4553fc..173eb58 100644 --- a/txselector/txselector.go +++ b/txselector/txselector.go @@ -67,34 +67,11 @@ func (txsel *TxSelector) Reset(batchNum common.BatchNum) error { return nil } -// GetL2TxSelection returns a selection of the L2Txs for the next batch, from the L2DB pool -func (txsel *TxSelector) GetL2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum) ([]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 - } - - // discard the txs that don't have an Account in the AccountDB - var validTxs txs - 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 - txs := txsel.getL2Profitable(validTxs, txsel.MaxTxs) - - // process the txs in the local AccountsDB - _, err = txsel.localAccountsDB.ProcessTxs(coordIdxs, nil, nil, txs) - if err != nil { - return nil, err - } - err = txsel.localAccountsDB.MakeCheckpoint() - return txs, err +// GetL2TxSelection returns the L1CoordinatorTxs and a selection of the L2Txs +// for the next batch, from the L2DB pool +func (txsel *TxSelector) GetL2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum) ([]common.L1Tx, []common.PoolL2Tx, error) { + _, l1CoordinatorTxs, l2Txs, err := txsel.GetL1L2TxSelection(coordIdxs, batchNum, []common.L1Tx{}) + return l1CoordinatorTxs, l2Txs, err } // GetL1L2TxSelection returns the selection of L1 + L2 txs @@ -138,7 +115,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(coordIdxs []common.Idx, batchNum com if l2TxsRaw[i].ToBJJ != nil { // case: ToBJJ!=0: // if idx exist for EthAddr&BJJ use it - _, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(l2TxsRaw[i].ToEthAddr, l2TxsRaw[i].ToBJJ) + _, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(l2TxsRaw[i].ToEthAddr, l2TxsRaw[i].ToBJJ, l2TxsRaw[i].TokenID) if err == nil { // account for ToEthAddr&ToBJJ already exist, // there is no need to create a new one. @@ -163,7 +140,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(coordIdxs []common.Idx, batchNum com } else { // case: ToBJJ==0: // if idx exist for EthAddr use it - _, err := txsel.localAccountsDB.GetIdxByEthAddr(l2TxsRaw[i].ToEthAddr) + _, err := txsel.localAccountsDB.GetIdxByEthAddr(l2TxsRaw[i].ToEthAddr, l2TxsRaw[i].TokenID) if err == nil { // account for ToEthAddr already exist, // there is no need to create a new one. @@ -194,7 +171,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(coordIdxs []common.Idx, batchNum com l1CoordinatorTxs = append(l1CoordinatorTxs, l1CoordinatorTx) } else if bytes.Equal(l2TxsRaw[i].ToEthAddr.Bytes(), common.FFAddr.Bytes()) && l2TxsRaw[i].ToBJJ != nil { // if idx exist for EthAddr&BJJ use it - _, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(l2TxsRaw[i].ToEthAddr, l2TxsRaw[i].ToBJJ) + _, err := txsel.localAccountsDB.GetIdxByEthAddrBJJ(l2TxsRaw[i].ToEthAddr, l2TxsRaw[i].ToBJJ, l2TxsRaw[i].TokenID) if err == nil { // account for ToEthAddr&ToBJJ already exist, (where ToEthAddr==0xff) // there is no need to create a new one. diff --git a/txselector/txselector_test.go b/txselector/txselector_test.go index ef5c4dd..8ea3dd3 100644 --- a/txselector/txselector_test.go +++ b/txselector/txselector_test.go @@ -1,7 +1,26 @@ package txselector -/* - TODO update transactions generation +import ( + "io/ioutil" + "os" + "strconv" + "testing" + "time" + + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/hermeznetwork/hermez-node/common" + dbUtils "github.com/hermeznetwork/hermez-node/db" + "github.com/hermeznetwork/hermez-node/db/historydb" + "github.com/hermeznetwork/hermez-node/db/l2db" + "github.com/hermeznetwork/hermez-node/db/statedb" + "github.com/hermeznetwork/hermez-node/eth" + "github.com/hermeznetwork/hermez-node/test" + "github.com/hermeznetwork/hermez-node/test/til" + "github.com/jmoiron/sqlx" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + func initTest(t *testing.T, testSet string, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) *TxSelector { pass := os.Getenv("POSTGRES_PASS") db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez") @@ -42,34 +61,67 @@ func TestGetL2TxSelection(t *testing.T) { txsel := initTest(t, til.SetPool0, 5, 5, 10) test.CleanL2DB(txsel.l2db.DB()) - // generate test transactions - l1Txs, _, poolL2Txs, tokens := test.GenerateTestTxsFromSet(t, test.SetTest0) + tc := til.NewContext(eth.RollupConstMaxL1UserTx) + // generate test transactions + blocks, err := tc.GenerateBlocks(til.SetBlockchain0) + assert.Nil(t, err) + // poolL2Txs, err := tc.GeneratePoolL2Txs(til.SetPool0) + // assert.Nil(t, err) + + coordIdxs := []common.Idx{256, 257, 258, 259} + + // add tokens to HistoryDB to avoid breaking FK constrains + var tokens []common.Token + for i := 0; i < int(tc.LastRegisteredTokenID); i++ { + tokens = append(tokens, common.Token{ + TokenID: common.TokenID(i), + EthBlockNum: 1, + EthAddr: ethCommon.BytesToAddress([]byte{byte(i)}), + Name: strconv.Itoa(i), + Symbol: strconv.Itoa(i), + Decimals: 18, + }) + } + addTokens(t, tokens, txsel.l2db.DB()) + + // Process the 1st batch, which contains the L1CoordinatorTxs necessary + // to create the Coordinator accounts to receive the fees + _, err = txsel.localAccountsDB.ProcessTxs(nil, nil, blocks[0].Batches[0].L1CoordinatorTxs, nil) + require.Nil(t, err) - // add tokens to HistoryDB to avoid breaking FK constrains - addTokens(t, tokens, txsel.l2db.DB()) - // add the first batch of transactions to the TxSelector - addL2Txs(t, txsel, poolL2Txs[0]) + // add the 1st batch of transactions to the TxSelector + addL2Txs(t, txsel, common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs)) - _, err := txsel.GetL2TxSelection(0) - assert.Nil(t, err) + l1CoordTxs, l2Txs, err := txsel.GetL2TxSelection(coordIdxs, 0) + assert.Nil(t, err) + assert.Equal(t, 0, len(l2Txs)) + assert.Equal(t, 0, len(l1CoordTxs)) - _, _, _, err = txsel.GetL1L2TxSelection(0, l1Txs[0]) - assert.Nil(t, err) + _, _, _, err = txsel.GetL1L2TxSelection(coordIdxs, 0, blocks[0].L1UserTxs) + assert.Nil(t, err) - // TODO once L2DB is updated to return error in case that AddTxTest - // fails, and the Til is updated, update this test, checking that the - // selected PoolL2Tx are correctly sorted by Nonce + // TODO once L2DB is updated to return error in case that AddTxTest + // fails, and the Til is updated, update this test, checking that the + // selected PoolL2Tx are correctly sorted by Nonce + // TODO once L2DB is updated to store the parameter AbsoluteFee (which + // is used by TxSelector to sort L2Txs), uncomment this next lines of + // test, and put the expected value for + // l2Txs[len(l2Txs)-1].AbsoluteFee, which is the Tx which has the + // Fee==192. + /* + // add the 3rd batch of transactions to the TxSelector + addL2Txs(t, txsel, common.L2TxsToPoolL2Txs(blocks[0].Batches[2].L2Txs)) + _, l2Txs, err = txsel.GetL2TxSelection(coordIdxs, 0) + assert.Nil(t, err) + for _, tx := range l2Txs { + fmt.Println(tx.FromIdx, tx.ToIdx, tx.AbsoluteFee) + } + require.Equal(t, 10, len(l2Txs)) + assert.Equal(t, float64(0), l2Txs[0].AbsoluteFee) - // txs, err := txsel.GetL2TxSelection(0) - // assert.Nil(t, err) - // for _, tx := range txs { - // fmt.Println(tx.FromIdx, tx.ToIdx, tx.AbsoluteFee) - // } - // assert.Equal(t, 3, len(txs)) - // assert.Equal(t, uint64(6), txs[0].AbsoluteFee) - // assert.Equal(t, uint64(5), txs[1].AbsoluteFee) - // assert.Equal(t, uint64(4), txs[2].AbsoluteFee) + fmt.Println(l2Txs[len(l2Txs)-1].Amount) + assert.Equal(t, float64(4), l2Txs[len(l2Txs)-1].AbsoluteFee) + */ } -*/