Browse Source

Add Til set w minimum flow, small fixes at StateDB

feature/sql-semaphore1
arnaucube 4 years ago
parent
commit
f65a6047b4
8 changed files with 319 additions and 27 deletions
  1. +3
    -0
      db/statedb/statedb.go
  2. +6
    -3
      db/statedb/txprocessors.go
  3. +135
    -2
      db/statedb/txprocessors_test.go
  4. +7
    -5
      db/statedb/utils.go
  5. +3
    -1
      db/statedb/utils_test.go
  6. +128
    -0
      test/til/sets.go
  7. +10
    -1
      test/til/sets_test.go
  8. +27
    -15
      test/til/txs.go

+ 3
- 0
db/statedb/statedb.go

@ -28,6 +28,9 @@ var (
// ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr // ErrToIdxNotFound is used when trying to get the ToIdx from ToEthAddr
// or ToEthAddr&ToBJJ // or ToEthAddr&ToBJJ
ErrToIdxNotFound = errors.New("ToIdx can not be found") ErrToIdxNotFound = errors.New("ToIdx can not be found")
// ErrGetIdxNoCase is used when trying to get the Idx from EthAddr &
// BJJ with not compatible combination
ErrGetIdxNoCase = errors.New("Can not get Idx due unexpected combination of ethereum Address & BabyJubJub PublicKey")
// KeyCurrentBatch is used as key in the db to store the current BatchNum // KeyCurrentBatch is used as key in the db to store the current BatchNum
KeyCurrentBatch = []byte("k:currentbatch") KeyCurrentBatch = []byte("k:currentbatch")

+ 6
- 3
db/statedb/txprocessors.go

@ -264,7 +264,7 @@ func (s *StateDB) getTokenIDsBigInt(l1usertxs, l1coordinatortxs []common.L1Tx, l
// AccountsDB (in the StateDB) // AccountsDB (in the StateDB)
acc, err := s.GetAccount(l2txs[i].FromIdx) acc, err := s.GetAccount(l2txs[i].FromIdx)
if err != nil { if err != nil {
log.Errorf("ToIdx %d not found: %s", l2txs[i].ToIdx, err.Error())
log.Errorf("could not get account to determine TokenID of L2Tx: FromIdx %d not found: %s", l2txs[i].FromIdx, err.Error())
return nil, err return nil, err
} }
tokenIDs[acc.TokenID] = true tokenIDs[acc.TokenID] = true
@ -397,7 +397,6 @@ func (s *StateDB) processL2Tx(coordIdxsMap map[common.TokenID]common.Idx, collec
// 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.TokenID) tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ, tx.TokenID)
if err != nil { if err != nil {
log.Error(err)
return nil, nil, false, err return nil, nil, false, err
} }
} }
@ -607,6 +606,7 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, coll
fee := common.CalcFeeAmount(tx.Amount, *tx.Fee) fee := common.CalcFeeAmount(tx.Amount, *tx.Fee)
feeAndAmount := new(big.Int).Add(tx.Amount, fee) feeAndAmount := new(big.Int).Add(tx.Amount, fee)
accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount) accSender.Balance = new(big.Int).Sub(accSender.Balance, feeAndAmount)
// send the fee to the Idx of the Coordinator for the TokenID // send the fee to the Idx of the Coordinator for the TokenID
accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID]) accCoord, err := s.GetAccount(coordIdxsMap[accSender.TokenID])
if err != nil { if err != nil {
@ -623,6 +623,8 @@ func (s *StateDB) applyTransfer(coordIdxsMap map[common.TokenID]common.Idx, coll
collected.Add(collected, fee) collected.Add(collected, fee)
} }
} }
} else {
accSender.Balance = new(big.Int).Sub(accSender.Balance, tx.Amount)
} }
// add amount-feeAmount to the receiver // add amount-feeAmount to the receiver
@ -676,7 +678,6 @@ func (s *StateDB) applyCreateAccountDepositTransfer(tx *common.L1Tx) error {
PublicKey: tx.FromBJJ, PublicKey: tx.FromBJJ,
EthAddr: tx.FromEthAddr, EthAddr: tx.FromEthAddr,
} }
accSender.Balance = new(big.Int).Add(accSender.Balance, tx.LoadAmount)
accReceiver, err := s.GetAccount(tx.ToIdx) accReceiver, err := s.GetAccount(tx.ToIdx)
if err != nil { if err != nil {
return err return err
@ -762,6 +763,8 @@ func (s *StateDB) applyExit(coordIdxsMap map[common.TokenID]common.Idx, collecte
collected.Add(collected, fee) collected.Add(collected, fee)
} }
} }
} else {
acc.Balance = new(big.Int).Sub(acc.Balance, tx.Amount)
} }
p, err := s.UpdateAccount(tx.FromIdx, acc) p, err := s.UpdateAccount(tx.FromIdx, acc)

+ 135
- 2
db/statedb/txprocessors_test.go

@ -15,6 +15,139 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func checkBalance(t *testing.T, tc *til.Context, sdb *StateDB, username string, tokenid int, expected string) {
idx := tc.Users[username].Accounts[common.TokenID(tokenid)].Idx
acc, err := sdb.GetAccount(idx)
require.Nil(t, err)
assert.Equal(t, expected, acc.Balance.String())
}
func TestProcessTxsBalances(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err)
defer assert.Nil(t, os.RemoveAll(dir))
sdb, err := NewStateDB(dir, TypeSynchronizer, 32)
assert.Nil(t, err)
// generate test transactions from test.SetBlockchain0 code
tc := til.NewContext(eth.RollupConstMaxL1UserTx)
blocks, err := tc.GenerateBlocks(til.SetBlockchainMinimumFlow0)
require.Nil(t, err)
// Coordinator Idx where to send the fees
coordIdxs := []common.Idx{256, 257}
log.Debug("block:0 batch:0, only L1CoordinatorTxs")
_, err = sdb.ProcessTxs(nil, nil, blocks[0].Batches[0].L1CoordinatorTxs, nil)
require.Nil(t, err)
log.Debug("block:0 batch:1")
l1UserTxs := []common.L1Tx{}
l2Txs := common.L2TxsToPoolL2Txs(blocks[0].Batches[1].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[1].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
log.Debug("block:0 batch:2")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[2].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[2].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[2].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "A", 0, "500")
log.Debug("block:0 batch:3")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[3].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[3].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[3].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "A", 0, "500")
checkBalance(t, tc, sdb, "A", 1, "500")
log.Debug("block:0 batch:4")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[4].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[4].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[4].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "A", 0, "500")
checkBalance(t, tc, sdb, "A", 1, "500")
log.Debug("block:0 batch:5")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[5].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[5].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[5].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "A", 0, "600")
checkBalance(t, tc, sdb, "A", 1, "500")
checkBalance(t, tc, sdb, "B", 0, "400")
log.Debug("block:0 batch:6")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[6].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[6].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[6].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "Coord", 0, "10")
checkBalance(t, tc, sdb, "Coord", 1, "20")
checkBalance(t, tc, sdb, "A", 0, "600")
checkBalance(t, tc, sdb, "A", 1, "280")
checkBalance(t, tc, sdb, "B", 0, "290")
checkBalance(t, tc, sdb, "B", 1, "200")
checkBalance(t, tc, sdb, "C", 0, "100")
checkBalance(t, tc, sdb, "D", 0, "800")
log.Debug("block:0 batch:7")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[0].Batches[7].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[0].Batches[7].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[0].Batches[7].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "Coord", 0, "35")
checkBalance(t, tc, sdb, "Coord", 1, "30")
checkBalance(t, tc, sdb, "A", 0, "430")
checkBalance(t, tc, sdb, "A", 1, "280")
checkBalance(t, tc, sdb, "B", 0, "390")
checkBalance(t, tc, sdb, "B", 1, "90")
checkBalance(t, tc, sdb, "C", 0, "45")
checkBalance(t, tc, sdb, "C", 1, "100")
checkBalance(t, tc, sdb, "D", 0, "800")
log.Debug("block:1 batch:0")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Batches[0].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[0].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Batches[0].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "Coord", 0, "75")
checkBalance(t, tc, sdb, "Coord", 1, "30")
checkBalance(t, tc, sdb, "A", 0, "730")
checkBalance(t, tc, sdb, "A", 1, "280")
checkBalance(t, tc, sdb, "B", 0, "380")
checkBalance(t, tc, sdb, "B", 1, "90")
checkBalance(t, tc, sdb, "C", 0, "845")
checkBalance(t, tc, sdb, "C", 1, "100")
checkBalance(t, tc, sdb, "D", 0, "470")
log.Debug("block:1 batch:1")
l1UserTxs = til.L1TxsToCommonL1Txs(tc.Queues[*blocks[1].Batches[1].Batch.ForgeL1TxsNum])
l2Txs = common.L2TxsToPoolL2Txs(blocks[1].Batches[1].L2Txs)
_, err = sdb.ProcessTxs(coordIdxs, l1UserTxs, blocks[1].Batches[1].L1CoordinatorTxs, l2Txs)
require.Nil(t, err)
// use Set of PoolL2 txs
poolL2Txs, err := tc.GeneratePoolL2Txs(til.SetPoolL2MinimumFlow0)
assert.Nil(t, err)
_, err = sdb.ProcessTxs(coordIdxs, []common.L1Tx{}, []common.L1Tx{}, poolL2Txs)
require.Nil(t, err)
checkBalance(t, tc, sdb, "Coord", 0, "105")
checkBalance(t, tc, sdb, "Coord", 1, "40")
checkBalance(t, tc, sdb, "A", 0, "510")
checkBalance(t, tc, sdb, "A", 1, "170")
checkBalance(t, tc, sdb, "B", 0, "480")
checkBalance(t, tc, sdb, "B", 1, "190")
checkBalance(t, tc, sdb, "C", 0, "845")
checkBalance(t, tc, sdb, "C", 1, "100")
checkBalance(t, tc, sdb, "D", 0, "360")
checkBalance(t, tc, sdb, "F", 0, "100")
}
func TestProcessTxsSynchronizer(t *testing.T) { func TestProcessTxsSynchronizer(t *testing.T) {
dir, err := ioutil.TempDir("", "tmpdb") dir, err := ioutil.TempDir("", "tmpdb")
require.Nil(t, err) require.Nil(t, err)
@ -121,7 +254,7 @@ func TestProcessTxsSynchronizer(t *testing.T) {
assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String()) assert.Equal(t, "0", ptOut.CollectedFees[common.TokenID(3)].String())
acc, err = sdb.GetAccount(idxA1) acc, err = sdb.GetAccount(idxA1)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "82", acc.Balance.String())
assert.Equal(t, "77", acc.Balance.String())
idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
acc, err = sdb.GetAccount(idxB0) acc, err = sdb.GetAccount(idxB0)
@ -195,7 +328,7 @@ func TestProcessTxsBatchBuilder(t *testing.T) {
require.Nil(t, err) require.Nil(t, err)
acc, err = sdb.GetAccount(idxA1) acc, err = sdb.GetAccount(idxA1)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "82", acc.Balance.String())
assert.Equal(t, "77", acc.Balance.String())
idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx idxB0 := tc.Users["C"].Accounts[common.TokenID(0)].Idx
acc, err = sdb.GetAccount(idxB0) acc, err = sdb.GetAccount(idxB0)

+ 7
- 5
db/statedb/utils.go

@ -63,6 +63,7 @@ func (s *StateDB) setIdxByEthAddrBJJ(idx common.Idx, addr ethCommon.Address, pk
if err != nil { if err != nil {
return err return err
} }
// store Addr-idx // store Addr-idx
k = concatEthAddrTokenID(addr, tokenID) k = concatEthAddrTokenID(addr, tokenID)
err = tx.Put(append(PrefixKeyAddr, k...), idxBytes[:]) err = tx.Put(append(PrefixKeyAddr, k...), idxBytes[:])
@ -83,11 +84,11 @@ func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID
k := concatEthAddrTokenID(addr, tokenID) k := concatEthAddrTokenID(addr, tokenID)
b, err := s.db.Get(append(PrefixKeyAddr, k...)) b, err := s.db.Get(append(PrefixKeyAddr, k...))
if err != nil { if err != nil {
return common.Idx(0), ErrToIdxNotFound
return common.Idx(0), fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d", ErrToIdxNotFound, addr.Hex(), tokenID)
} }
idx, err := common.IdxFromBytes(b) idx, err := common.IdxFromBytes(b)
if err != nil { if err != nil {
return common.Idx(0), ErrToIdxNotFound
return common.Idx(0), fmt.Errorf("GetIdxByEthAddr: %s: ToEthAddr: %s, TokenID: %d", err, addr.Hex(), tokenID)
} }
return idx, nil return idx, nil
} }
@ -99,6 +100,7 @@ func (s *StateDB) GetIdxByEthAddr(addr ethCommon.Address, tokenID common.TokenID
// the StateDB. // the StateDB.
func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicKey, tokenID common.TokenID) (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 {
// ToEthAddr
// case ToEthAddr!=0 && ToBJJ=0 // case ToEthAddr!=0 && ToBJJ=0
return s.GetIdxByEthAddr(addr, tokenID) 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 {
@ -106,16 +108,16 @@ func (s *StateDB) GetIdxByEthAddrBJJ(addr ethCommon.Address, pk *babyjub.PublicK
k := concatEthAddrBJJTokenID(addr, pk, tokenID) 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), fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrToIdxNotFound, addr.Hex(), pk, tokenID)
} }
idx, err := common.IdxFromBytes(b) idx, err := common.IdxFromBytes(b)
if err != nil { if err != nil {
return common.Idx(0), ErrToIdxNotFound
return common.Idx(0), fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", err, addr.Hex(), pk, tokenID)
} }
return idx, nil return idx, nil
} }
// rest of cases (included case ToEthAddr==0) are not possible // rest of cases (included case ToEthAddr==0) are not possible
return common.Idx(0), ErrToIdxNotFound
return common.Idx(0), fmt.Errorf("GetIdxByEthAddrBJJ: Not found, %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrGetIdxNoCase, addr.Hex(), pk, tokenID)
} }
func (s *StateDB) getTokenIDsFromIdxs(idxs []common.Idx) (map[common.TokenID]common.Idx, error) { func (s *StateDB) getTokenIDsFromIdxs(idxs []common.Idx) (map[common.TokenID]common.Idx, error) {

+ 3
- 1
db/statedb/utils_test.go

@ -1,6 +1,7 @@
package statedb package statedb
import ( import (
"fmt"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
@ -82,7 +83,8 @@ func TestGetIdx(t *testing.T) {
// 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, tokenID0) idxR, err = sdb.GetIdxByEthAddrBJJ(addr2, pk2, tokenID0)
assert.NotNil(t, err) assert.NotNil(t, err)
assert.Equal(t, ErrToIdxNotFound, err)
expectedErr := fmt.Errorf("GetIdxByEthAddrBJJ: %s: ToEthAddr: %s, ToBJJ: %s, TokenID: %d", ErrToIdxNotFound, addr2.Hex(), pk2, tokenID0)
assert.Equal(t, expectedErr, 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 // expect error when trying to get Idx by addr with not used TokenID
_, err = sdb.GetIdxByEthAddr(addr, tokenID1) _, err = sdb.GetIdxByEthAddr(addr, tokenID1)

+ 128
- 0
test/til/sets.go

@ -202,3 +202,131 @@ PoolTransfer(1) A-C: 3 (1)
PoolTransferToEthAddr(1) A-C: 3 (1) PoolTransferToEthAddr(1) A-C: 3 (1)
PoolTransferToBJJ(1) A-C: 3 (1) PoolTransferToBJJ(1) A-C: 3 (1)
` `
// Minimum flow
// SetBlockchainMinimumFlow0 contains a set of transactions with a minimal flow
var SetBlockchainMinimumFlow0 = `
Type: Blockchain
AddToken(1)
// Coordinator accounts, Idxs: 256, 257
CreateAccountCoordinator(0) Coord
CreateAccountCoordinator(1) Coord
// close Block:0, Batch:0
> batch // forge L1Coord{2}
CreateAccountDeposit(0) A: 500
CreateAccountDeposit(1) C: 0
CreateAccountCoordinator(0) C
// close Block:0, Batch:1
> batchL1 // freeze L1User{2}, forge L1Coord{1}
// Expected balances:
// Coord(0): 0, Coord(1): 0
// C(0): 0
CreateAccountDeposit(1) A: 500
// close Block:0, Batch:2
> batchL1 // freeze L1User{1}, forge L1User{2}
// Expected balances:
// Coord(0): 0, Coord(1): 0
// A(0): 500
// C(0): 0, C(1): 0
// close Block:0, Batch:3
> batchL1 // freeze L1User{nil}, forge L1User{1}
// Expected balances:
// Coord(0): 0, Coord(1): 0
// A(0): 500, A(1): 500
// C(0): 0
CreateAccountDepositTransfer(0) B-A: 500, 100
// close Block:0, Batch:4
> batchL1 // freeze L1User{1}, forge L1User{nil}
CreateAccountDeposit(0) D: 800
// close Block:0, Batch:5
> batchL1 // freeze L1User{1}, forge L1User{1}
// Expected balances:
// Coord(0): 0, Coord(1): 0
// A(0): 600, A(1): 500
// B(0): 400
// C(0): 0
CreateAccountCoordinator(1) B
Transfer(1) A-B: 200 (200)
Transfer(0) B-C: 100 (200)
// close Block:0, Batch:6
> batchL1 // forge L1User{1}, forge L1Coord{2}, forge L2{2}
// Expected balances:
// Coord(0): 10, Coord(1): 20
// A(0): 600, A(1): 280
// B(0): 290, B(1): 200
// C(0): 100, C(1): 0
// D(0): 800
Deposit(0) C: 500
DepositTransfer(0) C-D: 400, 100
Transfer(0) A-B: 100 (200)
Transfer(0) C-A: 50 (200)
Transfer(1) B-C: 100 (200)
Exit(0) A: 100 (200)
ForceTransfer(0) D-B: 200
ForceExit(0) B: 100
// close Block:0, Batch:7
> batchL1 // freeze L1User{4}, forge L1User{nil}, forge L2{4}
> block
// Expected balances:
// Coord(0): 35, Coord(1): 30
// A(0): 430, A(1): 280
// B(0): 390, B(1): 90
// C(0): 45, C(1): 100
// D(0): 800
Transfer(0) D-A: 300 (200)
Transfer(0) B-D: 100 (200)
// close Block:1, Batch:0
> batchL1 // freeze L1User{nil}, forge L1User{4}, forge L2{1}
// Expected balances:
// Coord(0): 75, Coord(1): 30
// A(0): 730, A(1): 280
// B(0): 380, B(1): 90
// C(0): 845, C(1): 100
// D(0): 470
CreateAccountCoordinator(0) F
> batch // forge L1CoordinatorTx{1}
> block
`
// SetPoolL2MinimumFlow0 contains a set of transactions with a minimal flow
var SetPoolL2MinimumFlow0 = `
Type: PoolL2
PoolTransfer(0) A-B: 100 (200)
PoolTransferToEthAddr(0) D-F: 100 (200)
PoolExit(0) A: 100 (200)
PoolTransferToEthAddr(1) A-B: 100 (200)
// Expected balances:
// Coord(0): 105, Coord(1): 40
// A(0): 510, A(1): 170
// B(0): 480, B(1): 190
// C(0): 845, C(1): 100
// D(0): 360
// F(0): 100
`

+ 10
- 1
test/til/sets_test.go

@ -8,7 +8,7 @@ import (
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestCompileSets(t *testing.T) {
func TestCompileSetsBase(t *testing.T) {
parser := newParser(strings.NewReader(SetBlockchain0)) parser := newParser(strings.NewReader(SetBlockchain0))
_, err := parser.parse() _, err := parser.parse()
assert.Nil(t, err) assert.Nil(t, err)
@ -22,3 +22,12 @@ func TestCompileSets(t *testing.T) {
_, err = tc.GeneratePoolL2Txs(SetPool0) _, err = tc.GeneratePoolL2Txs(SetPool0)
assert.Nil(t, err) assert.Nil(t, err)
} }
func TestCompileSetsMinimumFlow(t *testing.T) {
// minimum flow
tc := NewContext(eth.RollupConstMaxL1UserTx)
_, err := tc.GenerateBlocks(SetBlockchainMinimumFlow0)
assert.Nil(t, err)
_, err = tc.GeneratePoolL2Txs(SetPoolL2MinimumFlow0)
assert.Nil(t, err)
}

+ 27
- 15
test/til/txs.go

@ -49,8 +49,8 @@ type Context struct {
currBlock common.BlockData currBlock common.BlockData
currBatch common.BatchData currBatch common.BatchData
currBatchNum int currBatchNum int
queues [][]L1Tx
toForgeNum int
Queues [][]L1Tx
ToForgeNum int
openToForge int openToForge int
currBatchTest struct { currBatchTest struct {
l1CoordinatorTxs []L1Tx l1CoordinatorTxs []L1Tx
@ -75,8 +75,8 @@ func NewContext(rollupConstMaxL1UserTx int) *Context {
currBatch: newBatchData(currBatchNum), currBatch: newBatchData(currBatchNum),
currBatchNum: currBatchNum, currBatchNum: currBatchNum,
// start with 2 queues, one for toForge, and the other for openToForge // start with 2 queues, one for toForge, and the other for openToForge
queues: make([][]L1Tx, 2),
toForgeNum: 0,
Queues: make([][]L1Tx, 2),
ToForgeNum: 0,
openToForge: 1, openToForge: 1,
//nolint:gomnd //nolint:gomnd
blockNum: 2, // rollup genesis blockNum blockNum: 2, // rollup genesis blockNum
@ -301,8 +301,8 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
return nil, err return nil, err
} }
case typeNewBatchL1: case typeNewBatchL1:
// for each L1UserTx of the queues[ToForgeNum], calculate the Idx
if err = tc.calculateIdxForL1Txs(false, tc.queues[tc.toForgeNum]); err != nil {
// for each L1UserTx of the Queues[ToForgeNum], calculate the Idx
if err = tc.calculateIdxForL1Txs(false, tc.Queues[tc.ToForgeNum]); err != nil {
return nil, err return nil, err
} }
if err = tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil { if err = tc.calculateIdxForL1Txs(true, tc.currBatchTest.l1CoordinatorTxs); err != nil {
@ -313,12 +313,14 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
log.Error(err) log.Error(err)
return nil, err return nil, err
} }
toForgeL1TxsNum := int64(tc.openToForge)
tc.currBatch.Batch.ForgeL1TxsNum = &toForgeL1TxsNum
// advance batch // advance batch
tc.toForgeNum++
if tc.toForgeNum == tc.openToForge {
tc.ToForgeNum++
if tc.ToForgeNum == tc.openToForge {
tc.openToForge++ tc.openToForge++
newQueue := []L1Tx{} newQueue := []L1Tx{}
tc.queues = append(tc.queues, newQueue)
tc.Queues = append(tc.Queues, newQueue)
} }
case typeNewBlock: case typeNewBlock:
blocks = append(blocks, tc.currBlock) blocks = append(blocks, tc.currBlock)
@ -349,12 +351,12 @@ func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
// calculateIdxsForL1Txs calculates new Idx for new created accounts. If // calculateIdxsForL1Txs calculates new Idx for new created accounts. If
// 'isCoordinatorTxs==true', adds the tx to tc.currBatch.L1CoordinatorTxs. // 'isCoordinatorTxs==true', adds the tx to tc.currBatch.L1CoordinatorTxs.
func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error { func (tc *Context) calculateIdxForL1Txs(isCoordinatorTxs bool, txs []L1Tx) error {
// for each batch.L1CoordinatorTxs of the queues[ToForgeNum], calculate the Idx
// for each batch.L1CoordinatorTxs of the Queues[ToForgeNum], calculate the Idx
for i := 0; i < len(txs); i++ { for i := 0; i < len(txs); i++ {
tx := txs[i] tx := txs[i]
if tx.L1Tx.Type == common.TxTypeCreateAccountDeposit || tx.L1Tx.Type == common.TxTypeCreateAccountDepositTransfer { if tx.L1Tx.Type == common.TxTypeCreateAccountDeposit || tx.L1Tx.Type == common.TxTypeCreateAccountDepositTransfer {
if tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] != nil { // if account already exists, return error if tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] != nil { // if account already exists, return error
return fmt.Errorf("Can not create same account twice (same User & same TokenID) (this is a design property of Til)")
return fmt.Errorf("Can not create same account twice (same User (%s) & same TokenID (%d)) (this is a design property of Til)", tx.fromIdxName, tx.L1Tx.TokenID)
} }
tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{ tc.Users[tx.fromIdxName].Accounts[tx.L1Tx.TokenID] = &Account{
Idx: common.Idx(tc.idx), Idx: common.Idx(tc.idx),
@ -418,19 +420,19 @@ func (tc *Context) setIdxs() error {
// addToL1Queue adds the L1Tx into the queue that is open and has space // addToL1Queue adds the L1Tx into the queue that is open and has space
func (tc *Context) addToL1Queue(tx L1Tx) error { func (tc *Context) addToL1Queue(tx L1Tx) error {
if len(tc.queues[tc.openToForge]) >= tc.rollupConstMaxL1UserTx {
if len(tc.Queues[tc.openToForge]) >= tc.rollupConstMaxL1UserTx {
// if current OpenToForge queue reached its Max, move into a // if current OpenToForge queue reached its Max, move into a
// new queue // new queue
tc.openToForge++ tc.openToForge++
newQueue := []L1Tx{} newQueue := []L1Tx{}
tc.queues = append(tc.queues, newQueue)
tc.Queues = append(tc.Queues, newQueue)
} }
// Fill L1UserTx specific parameters // Fill L1UserTx specific parameters
tx.L1Tx.UserOrigin = true tx.L1Tx.UserOrigin = true
toForgeL1TxsNum := int64(tc.openToForge) toForgeL1TxsNum := int64(tc.openToForge)
tx.L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum tx.L1Tx.ToForgeL1TxsNum = &toForgeL1TxsNum
tx.L1Tx.EthBlockNum = tc.blockNum tx.L1Tx.EthBlockNum = tc.blockNum
tx.L1Tx.Position = len(tc.queues[tc.openToForge])
tx.L1Tx.Position = len(tc.Queues[tc.openToForge])
// When an L1UserTx is generated, all idxs must be available (except when idx == 0 or idx == 1) // When an L1UserTx is generated, all idxs must be available (except when idx == 0 or idx == 1)
if tx.L1Tx.Type != common.TxTypeCreateAccountDeposit && tx.L1Tx.Type != common.TxTypeCreateAccountDepositTransfer { if tx.L1Tx.Type != common.TxTypeCreateAccountDeposit && tx.L1Tx.Type != common.TxTypeCreateAccountDepositTransfer {
@ -457,7 +459,7 @@ func (tc *Context) addToL1Queue(tx L1Tx) error {
} }
tx.L1Tx = *nTx tx.L1Tx = *nTx
tc.queues[tc.openToForge] = append(tc.queues[tc.openToForge], tx)
tc.Queues[tc.openToForge] = append(tc.Queues[tc.openToForge], tx)
tc.currBlock.L1UserTxs = append(tc.currBlock.L1UserTxs, tx.L1Tx) tc.currBlock.L1UserTxs = append(tc.currBlock.L1UserTxs, tx.L1Tx)
return nil return nil
@ -554,6 +556,7 @@ func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
tx := common.PoolL2Tx{ tx := common.PoolL2Tx{
FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx, FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
ToIdx: common.Idx(1), // as is an Exit ToIdx: common.Idx(1), // as is an Exit
Fee: common.FeeSelector(inst.fee),
TokenID: inst.tokenID, TokenID: inst.tokenID,
Amount: big.NewInt(int64(inst.amount)), Amount: big.NewInt(int64(inst.amount)),
Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce, Nonce: tc.Users[inst.from].Accounts[inst.tokenID].Nonce,
@ -608,3 +611,12 @@ func (tc *Context) generateKeys(userNames []string) {
tc.Users[userNames[i-1]] = &u tc.Users[userNames[i-1]] = &u
} }
} }
// L1TxsToCommonL1Txs converts an array of []til.L1Tx to []common.L1Tx
func L1TxsToCommonL1Txs(l1 []L1Tx) []common.L1Tx {
var r []common.L1Tx
for i := 0; i < len(l1); i++ {
r = append(r, l1[i].L1Tx)
}
return r
}

Loading…
Cancel
Save