Browse Source

Merge pull request #233 from hermeznetwork/feature/sdb-idxdb-tokenid

StateDB store Idxs with TokenID at the db-key & TxSelector include L1CoordinatorTxs in selections
feature/sql-semaphore1
Eduard S 4 years ago
committed by GitHub
parent
commit
c1b9b0be90
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 139 additions and 90 deletions
  1. +2
    -2
      common/pooll2tx.go
  2. +1
    -1
      coordinator/coordinator.go
  3. +1
    -1
      db/l2db/l2db.go
  4. +1
    -1
      db/statedb/statedb.go
  5. +1
    -1
      db/statedb/txprocessors.go
  6. +2
    -0
      db/statedb/txprocessors_test.go
  7. +19
    -10
      db/statedb/utils.go
  8. +20
    -11
      db/statedb/utils_test.go
  9. +7
    -7
      test/til/txs.go
  10. +8
    -31
      txselector/txselector.go
  11. +77
    -25
      txselector/txselector_test.go

+ 2
- 2
common/pooll2tx.go

@ -22,7 +22,7 @@ type PoolL2Tx struct {
FromIdx Idx `meddler:"from_idx"` FromIdx Idx `meddler:"from_idx"`
ToIdx Idx `meddler:"to_idx,zeroisnull"` 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) 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"` ToBJJ *babyjub.PublicKey `meddler:"to_bjj"`
TokenID TokenID `meddler:"token_id"` TokenID TokenID `meddler:"token_id"`
Amount *big.Int `meddler:"amount,bigint"` // TODO: change to float16 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 // 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) 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) 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 RqToBJJ *babyjub.PublicKey `meddler:"rq_to_bjj"` // TODO: stop using json, use scanner/valuer
RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"` RqTokenID TokenID `meddler:"rq_token_id,zeroisnull"`
RqAmount *big.Int `meddler:"rq_amount,bigintnull"` // TODO: change to float16 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 { } else {
// 2b: only L2 txs // 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 { if err != nil {
return nil, err return nil, err
} }

+ 1
- 1
db/l2db/l2db.go

@ -82,7 +82,7 @@ func (l2db *L2DB) AddTxTest(tx *common.PoolL2Tx) error {
Amount: tx.Amount, Amount: tx.Amount,
Fee: tx.Fee, Fee: tx.Fee,
Nonce: tx.Nonce, Nonce: tx.Nonce,
State: tx.State,
State: common.PoolL2TxStatePending,
Signature: tx.Signature, Signature: tx.Signature,
RqToBJJ: tx.RqToBJJ, RqToBJJ: tx.RqToBJJ,
RqAmount: tx.RqAmount, RqAmount: tx.RqAmount,

+ 1
- 1
db/statedb/statedb.go

@ -372,7 +372,7 @@ func (s *StateDB) CreateAccount(idx common.Idx, account *common.Account) (*merkl
return cpp, err return cpp, err
} }
// store idx by EthAddr & BJJ // store idx by EthAddr & BJJ
err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey)
err = s.setIdxByEthAddrBJJ(idx, account.EthAddr, account.PublicKey, account.TokenID)
return cpp, err return cpp, err
} }

+ 1
- 1
db/statedb/txprocessors.go

@ -378,7 +378,7 @@ func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, exitTr
// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ // if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) { if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) {
// case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ // case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ
tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ, tx.TokenID)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
return nil, nil, false, err return nil, nil, false, err

+ 2
- 0
db/statedb/txprocessors_test.go

@ -44,6 +44,8 @@ func TestProcessTxsSynchronizer(t *testing.T) {
// Idx of user 'A' // Idx of user 'A'
idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx idxA1 := tc.Users["A"].Accounts[common.TokenID(1)].Idx
// Process the 1st batch, which contains the L1CoordinatorTxs necessary
// to create the Coordinator accounts to receive the fees
log.Debug("1st batch, 1st block, only L1CoordinatorTxs") log.Debug("1st batch, 1st block, only L1CoordinatorTxs")
ptOut, err := sdb.ProcessTxs(nil, nil, blocks[0].Batches[0].L1CoordinatorTxs, nil) ptOut, err := sdb.ProcessTxs(nil, nil, blocks[0].Batches[0].L1CoordinatorTxs, nil)
require.Nil(t, err) require.Nil(t, err)

+ 19
- 10
db/statedb/utils.go

@ -12,11 +12,18 @@ import (
"github.com/iden3/go-merkletree" "github.com/iden3/go-merkletree"
) )
func concatEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey) []byte {
func concatEthAddrTokenID(addr ethCommon.Address, tokenID common.TokenID) []byte {
var b []byte
b = append(b, addr.Bytes()...)
b = append(b[:], tokenID.Bytes()[:]...)
return b
}
func concatEthAddrBJJTokenID(addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) []byte {
pkComp := pk.Compress() pkComp := pk.Compress()
var b []byte var b []byte
b = append(b, addr.Bytes()...) b = append(b, addr.Bytes()...)
b = append(b[:], pkComp[:]...) b = append(b[:], pkComp[:]...)
b = append(b[:], tokenID.Bytes()[:]...)
return b return b
} }
@ -25,8 +32,8 @@ func concatEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey) []byte {
// - key: EthAddr & BabyJubJub PublicKey Compressed, value: idx // - key: EthAddr & BabyJubJub PublicKey Compressed, value: idx
// If Idx already exist for the given EthAddr & BJJ, the remaining Idx will be // If Idx already exist for the given EthAddr & BJJ, the remaining Idx will be
// always the smallest one. // always the smallest one.
func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk *babyjub.PublicKey) error {
oldIdx, err := s.GetIdxByEthAddrBJJ(addr, pk)
func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) error {
oldIdx, err := s.GetIdxByEthAddrBJJ(addr, pk, tokenID)
if err == nil { if err == nil {
// EthAddr & BJJ already have an Idx // EthAddr & BJJ already have an Idx
// check which Idx is smaller // check which Idx is smaller
@ -46,7 +53,7 @@ func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk
if err != nil { if err != nil {
return err return err
} }
k := concatEthAddrBJJ(addr, pk)
k := concatEthAddrBJJTokenID(addr, pk, tokenID)
// store Addr&BJJ-idx // store Addr&BJJ-idx
idxBytes, err := idx.Bytes() idxBytes, err := idx.Bytes()
if err != nil { if err != nil {
@ -57,7 +64,8 @@ func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk
return err return err
} }
// store Addr-idx // store Addr-idx
err = tx.Put(append(PrefixKeyAddr, addr.Bytes()...), idxBytes[:])
k = concatEthAddrTokenID(addr, tokenID)
err = tx.Put(append(PrefixKeyAddr, k...), idxBytes[:])
if err != nil { if err != nil {
return err return err
} }
@ -71,8 +79,9 @@ func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk
// GetIdxByEthAddr returns the smallest Idx in the StateDB for the given // GetIdxByEthAddr returns the smallest Idx in the StateDB for the given
// Ethereum Address. Will return common.Idx(0) and error in case that Idx is // Ethereum Address. Will return common.Idx(0) and error in case that Idx is
// not found in the StateDB. // not found in the StateDB.
func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address) (common.Idx, error) {
b, err := s.db.Get(append(PrefixKeyAddr, addr.Bytes()...))
func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID) (common.Idx, error) {
k := concatEthAddrTokenID(addr, tokenID)
b, err := s.db.Get(append(PrefixKeyAddr, k...))
if err != nil { if err != nil {
return common.Idx(0), ErrToIdxNotFound return common.Idx(0), ErrToIdxNotFound
} }
@ -88,13 +97,13 @@ func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address) (common.Idx, error) {
// address, it's ignored in the query. If `pk` is nil, it's ignored in the // address, it's ignored in the query. If `pk` is nil, it's ignored in the
// query. Will return common.Idx(0) and error in case that Idx is not found in // query. Will return common.Idx(0) and error in case that Idx is not found in
// the StateDB. // the StateDB.
func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey) (common.Idx, error) {
func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) (common.Idx, error) {
if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk == nil { if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk == nil {
// case ToEthAddr!=0 && ToBJJ=0 // case ToEthAddr!=0 && ToBJJ=0
return s.GetIdxByEthAddr(addr)
return s.GetIdxByEthAddr(addr, tokenID)
} else if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk != nil { } else if !bytes.Equal(addr.Bytes(), common.EmptyAddr.Bytes()) && pk != nil {
// case ToEthAddr!=0 && ToBJJ!=0 // case ToEthAddr!=0 && ToBJJ!=0
k := concatEthAddrBJJ(addr, pk)
k := concatEthAddrBJJTokenID(addr, pk, tokenID)
b, err := s.db.Get(append(PrefixKeyAddrBJJ, k...)) b, err := s.db.Get(append(PrefixKeyAddrBJJ, k...))
if err != nil { if err != nil {
return common.Idx(0), ErrToIdxNotFound return common.Idx(0), ErrToIdxNotFound

+ 20
- 11
db/statedb/utils_test.go

@ -33,51 +33,60 @@ func TestGetIdx(t *testing.T) {
idx2 := common.Idx(12345) idx2 := common.Idx(12345)
idx3 := common.Idx(1233) idx3 := common.Idx(1233)
tokenID0 := common.TokenID(0)
tokenID1 := common.TokenID(1)
// store the keys for idx by Addr & BJJ // store the keys for idx by Addr & BJJ
err = sdb.setIdxByEthAddrBJJ(idx, addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx, addr, pk, tokenID0)
require.Nil(t, err) require.Nil(t, err)
idxR, err := sdb.GetIdxByEthAddrBJJ(addr, pk)
idxR, err := sdb.GetIdxByEthAddrBJJ(addr, pk, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, idx, idxR) assert.Equal(t, idx, idxR)
// expect error when getting only by EthAddr, as value does not exist // expect error when getting only by EthAddr, as value does not exist
// in the db for only EthAddr // in the db for only EthAddr
_, err = sdb.GetIdxByEthAddr(addr)
_, err = sdb.GetIdxByEthAddr(addr, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
_, err = sdb.GetIdxByEthAddr(addr2)
_, err = sdb.GetIdxByEthAddr(addr2, tokenID0)
assert.NotNil(t, err)
// expect error when getting by EthAddr and BJJ, but for another TokenID
_, err = sdb.GetIdxByEthAddrBJJ(addr, pk, tokenID1)
assert.NotNil(t, err) assert.NotNil(t, err)
// expect to fail // expect to fail
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk, tokenID0)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, common.Idx(0), idxR) assert.Equal(t, common.Idx(0), idxR)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk2)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk2, tokenID0)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, common.Idx(0), idxR) assert.Equal(t, common.Idx(0), idxR)
// try to store bigger idx, will not affect as already exist a smaller // try to store bigger idx, will not affect as already exist a smaller
// Idx for that Addr & BJJ // Idx for that Addr & BJJ
err = sdb.setIdxByEthAddrBJJ(idx2, addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx2, addr, pk, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
// store smaller idx // store smaller idx
err = sdb.setIdxByEthAddrBJJ(idx3, addr, pk)
err = sdb.setIdxByEthAddrBJJ(idx3, addr, pk, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr, pk, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, idx3, idxR) assert.Equal(t, idx3, idxR)
// by EthAddr should work // by EthAddr should work
idxR, err = sdb.GetIdxByEthAddr(addr)
idxR, err = sdb.GetIdxByEthAddr(addr, tokenID0)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, idx3, idxR) assert.Equal(t, idx3, idxR)
// expect error when trying to get Idx by addr2 & pk2 // expect error when trying to get Idx by addr2 & pk2
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk2)
idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk2, tokenID0)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, ErrToIdxNotFound, err) assert.Equal(t, ErrToIdxNotFound, err)
assert.Equal(t, common.Idx(0), idxR) assert.Equal(t, common.Idx(0), idxR)
// expect error when trying to get Idx by addr with not used TokenID
_, err = sdb.GetIdxByEthAddr(addr, tokenID1)
assert.NotNil(t, err)
} }
func TestBJJCompressedTo256BigInt(t *testing.T) { func TestBJJCompressedTo256BigInt(t *testing.T) {

+ 7
- 7
test/til/txs.go

@ -30,7 +30,7 @@ type Context struct {
Instructions []instruction Instructions []instruction
userNames []string userNames []string
Users map[string]*User Users map[string]*User
lastRegisteredTokenID common.TokenID
LastRegisteredTokenID common.TokenID
l1CreatedAccounts map[string]*Account l1CreatedAccounts map[string]*Account
// rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch // rollupConstMaxL1UserTx Maximum L1-user transactions allowed to be queued in a batch
@ -56,7 +56,7 @@ func NewContext(rollupConstMaxL1UserTx int) *Context {
return &Context{ return &Context{
Users: make(map[string]*User), Users: make(map[string]*User),
l1CreatedAccounts: make(map[string]*Account), l1CreatedAccounts: make(map[string]*Account),
lastRegisteredTokenID: 0,
LastRegisteredTokenID: 0,
rollupConstMaxL1UserTx: rollupConstMaxL1UserTx, rollupConstMaxL1UserTx: rollupConstMaxL1UserTx,
idx: common.UserThreshold, idx: common.UserThreshold,
@ -323,10 +323,10 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
TokenID: inst.tokenID, TokenID: inst.tokenID,
EthBlockNum: tc.blockNum, 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) tc.currBlock.AddedTokens = append(tc.currBlock.AddedTokens, newToken)
default: default:
return nil, fmt.Errorf("Line %d: Unexpected type: %s", inst.lineNum, inst.typ) 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 return nil
} }
func (tc *Context) checkIfTokenIsRegistered(inst instruction) error { 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 return nil
} }

+ 8
- 31
txselector/txselector.go

@ -67,34 +67,11 @@ func (txsel *TxSelector) Reset(batchNum common.BatchNum) error {
return nil 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 // 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 { if l2TxsRaw[i].ToBJJ != nil {
// case: ToBJJ!=0: // case: ToBJJ!=0:
// if idx exist for EthAddr&BJJ use it // 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 { if err == nil {
// account for ToEthAddr&ToBJJ already exist, // account for ToEthAddr&ToBJJ already exist,
// there is no need to create a new one. // there is no need to create a new one.
@ -163,7 +140,7 @@ func (txsel *TxSelector) GetL1L2TxSelection(coordIdxs []common.Idx, batchNum com
} else { } else {
// case: ToBJJ==0: // case: ToBJJ==0:
// if idx exist for EthAddr use it // 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 { if err == nil {
// account for ToEthAddr already exist, // account for ToEthAddr already exist,
// there is no need to create a new one. // 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) l1CoordinatorTxs = append(l1CoordinatorTxs, l1CoordinatorTx)
} else if bytes.Equal(l2TxsRaw[i].ToEthAddr.Bytes(), common.FFAddr.Bytes()) && l2TxsRaw[i].ToBJJ != nil { } else if bytes.Equal(l2TxsRaw[i].ToEthAddr.Bytes(), common.FFAddr.Bytes()) && l2TxsRaw[i].ToBJJ != nil {
// if idx exist for EthAddr&BJJ use it // 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 { if err == nil {
// account for ToEthAddr&ToBJJ already exist, (where ToEthAddr==0xff) // account for ToEthAddr&ToBJJ already exist, (where ToEthAddr==0xff)
// there is no need to create a new one. // there is no need to create a new one.

+ 77
- 25
txselector/txselector_test.go

@ -1,7 +1,26 @@
package txselector 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 { func initTest(t *testing.T, testSet string, maxL1UserTxs, maxL1OperatorTxs, maxTxs uint64) *TxSelector {
pass := os.Getenv("POSTGRES_PASS") pass := os.Getenv("POSTGRES_PASS")
db, err := dbUtils.InitSQLDB(5432, "localhost", "hermez", pass, "hermez") 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) txsel := initTest(t, til.SetPool0, 5, 5, 10)
test.CleanL2DB(txsel.l2db.DB()) 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