mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Merge pull request #233 from hermeznetwork/feature/sdb-idxdb-tokenid
StateDB store Idxs with TokenID at the db-key & TxSelector include L1CoordinatorTxs in selections
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) error {
|
||||||
oldIdx, err := s.GetIdxByEthAddrBJJ(addr, pk)
|
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) {
|
func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID) (common.Idx, error) {
|
||||||
b, err := s.db.Get(append(PrefixKeyAddr, addr.Bytes()...))
|
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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 {
|
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)
|
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 {
|
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 fmt.Errorf("Can not process %s: TokenID %d not registered, last registered TokenID: %d", inst.typ, inst.tokenID, tc.LastRegisteredTokenID)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// GetL2TxSelection returns the L1CoordinatorTxs and a selection of the L2Txs
|
||||||
func (txsel *TxSelector) GetL2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum) ([]common.PoolL2Tx, error) {
|
// for the next batch, from the L2DB pool
|
||||||
// get pending l2-tx from tx-pool
|
func (txsel *TxSelector) GetL2TxSelection(coordIdxs []common.Idx, batchNum common.BatchNum) ([]common.L1Tx, []common.PoolL2Tx, error) {
|
||||||
l2TxsRaw, err := txsel.l2db.GetPendingTxs() // once l2db ready, maybe use parameter 'batchNum'
|
_, l1CoordinatorTxs, l2Txs, err := txsel.GetL1L2TxSelection(coordIdxs, batchNum, []common.L1Tx{})
|
||||||
if err != nil {
|
return l1CoordinatorTxs, l2Txs, err
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
|
|||||||
@@ -1,7 +1,26 @@
|
|||||||
package txselector
|
package txselector
|
||||||
|
|
||||||
/*
|
import (
|
||||||
TODO update transactions generation
|
"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
|
tc := til.NewContext(eth.RollupConstMaxL1UserTx)
|
||||||
l1Txs, _, poolL2Txs, tokens := test.GenerateTestTxsFromSet(t, test.SetTest0)
|
// generate test transactions
|
||||||
|
blocks, err := tc.GenerateBlocks(til.SetBlockchain0)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
// poolL2Txs, err := tc.GeneratePoolL2Txs(til.SetPool0)
|
||||||
|
// assert.Nil(t, err)
|
||||||
|
|
||||||
// add tokens to HistoryDB to avoid breaking FK constrains
|
coordIdxs := []common.Idx{256, 257, 258, 259}
|
||||||
addTokens(t, tokens, txsel.l2db.DB())
|
|
||||||
// add the first batch of transactions to the TxSelector
|
|
||||||
addL2Txs(t, txsel, poolL2Txs[0])
|
|
||||||
|
|
||||||
_, err := txsel.GetL2TxSelection(0)
|
// add tokens to HistoryDB to avoid breaking FK constrains
|
||||||
assert.Nil(t, err)
|
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())
|
||||||
|
|
||||||
_, _, _, err = txsel.GetL1L2TxSelection(0, l1Txs[0])
|
// Process the 1st batch, which contains the L1CoordinatorTxs necessary
|
||||||
assert.Nil(t, err)
|
// 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)
|
||||||
|
|
||||||
// TODO once L2DB is updated to return error in case that AddTxTest
|
// add the 1st batch of transactions to the TxSelector
|
||||||
// fails, and the Til is updated, update this test, checking that the
|
addL2Txs(t, txsel, common.L2TxsToPoolL2Txs(blocks[0].Batches[0].L2Txs))
|
||||||
// selected PoolL2Tx are correctly sorted by Nonce
|
|
||||||
|
|
||||||
|
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(coordIdxs, 0, blocks[0].L1UserTxs)
|
||||||
|
assert.Nil(t, err)
|
||||||
|
|
||||||
// txs, err := txsel.GetL2TxSelection(0)
|
// TODO once L2DB is updated to return error in case that AddTxTest
|
||||||
// assert.Nil(t, err)
|
// fails, and the Til is updated, update this test, checking that the
|
||||||
// for _, tx := range txs {
|
// selected PoolL2Tx are correctly sorted by Nonce
|
||||||
// fmt.Println(tx.FromIdx, tx.ToIdx, tx.AbsoluteFee)
|
|
||||||
// }
|
// TODO once L2DB is updated to store the parameter AbsoluteFee (which
|
||||||
// assert.Equal(t, 3, len(txs))
|
// is used by TxSelector to sort L2Txs), uncomment this next lines of
|
||||||
// assert.Equal(t, uint64(6), txs[0].AbsoluteFee)
|
// test, and put the expected value for
|
||||||
// assert.Equal(t, uint64(5), txs[1].AbsoluteFee)
|
// l2Txs[len(l2Txs)-1].AbsoluteFee, which is the Tx which has the
|
||||||
// assert.Equal(t, uint64(4), txs[2].AbsoluteFee)
|
// 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)
|
||||||
|
|
||||||
|
fmt.Println(l2Txs[len(l2Txs)-1].Amount)
|
||||||
|
assert.Equal(t, float64(4), l2Txs[len(l2Txs)-1].AbsoluteFee)
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|||||||
Reference in New Issue
Block a user