Browse Source

TxSelector include L1CoordinatorTxs in selections

feature/sql-semaphore1
arnaucube 4 years ago
parent
commit
1203ab3865
6 changed files with 96 additions and 67 deletions
  1. +2
    -2
      common/pooll2tx.go
  2. +1
    -1
      coordinator/coordinator.go
  3. +1
    -1
      db/l2db/l2db.go
  4. +7
    -7
      test/til/txs.go
  5. +8
    -31
      txselector/txselector.go
  6. +77
    -25
      txselector/txselector_test.go

+ 2
- 2
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

+ 1
- 1
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
}

+ 1
- 1
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,

+ 7
- 7
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
}

+ 8
- 31
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.

+ 77
- 25
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)
*/
}
*/

Loading…
Cancel
Save