mirror of
https://github.com/arnaucube/hermez-node.git
synced 2026-02-07 11:26:44 +01:00
Add TxTypeTransferToEthAddr&ToBJJ to StateDB & Til
Add TxTypeTransferToEthAddr&ToBJJ to StateDB & Til resolves #203, resolves #209
This commit is contained in:
@@ -331,6 +331,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
|
||||
var err error
|
||||
// if tx.ToIdx==0, get toIdx by ToEthAddr or ToBJJ
|
||||
if tx.ToIdx == common.Idx(0) && tx.AuxToIdx == common.Idx(0) {
|
||||
// case when tx.Type== common.TxTypeTransferToEthAddr or common.TxTypeTransferToBJJ
|
||||
tx.AuxToIdx, err = s.GetIdxByEthAddrBJJ(tx.ToEthAddr, tx.ToBJJ)
|
||||
if err != nil {
|
||||
log.Error(err)
|
||||
@@ -390,7 +391,7 @@ func (s *StateDB) processL2Tx(exitTree *merkletree.MerkleTree, tx *common.PoolL2
|
||||
}
|
||||
|
||||
switch tx.Type {
|
||||
case common.TxTypeTransfer:
|
||||
case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
|
||||
// go to the MT account of sender and receiver, and update
|
||||
// balance & nonce
|
||||
err = s.applyTransfer(tx.Tx(), tx.AuxToIdx)
|
||||
|
||||
@@ -70,9 +70,9 @@ type instruction struct {
|
||||
|
||||
// parsedSet contains the full Set of Instructions representing a full code
|
||||
type parsedSet struct {
|
||||
// type string
|
||||
typ setType
|
||||
instructions []instruction
|
||||
accounts []string
|
||||
users []string
|
||||
}
|
||||
|
||||
func (i instruction) String() string {
|
||||
@@ -365,6 +365,12 @@ func (p *parser) parseLine(setType setType) (*instruction, error) {
|
||||
case "PoolTransfer":
|
||||
c.typ = common.TxTypeTransfer
|
||||
transferring = true
|
||||
case "PoolTransferToEthAddr":
|
||||
c.typ = common.TxTypeTransferToEthAddr
|
||||
transferring = true
|
||||
case "PoolTransferToBJJ":
|
||||
c.typ = common.TxTypeTransferToBJJ
|
||||
transferring = true
|
||||
case "PoolExit":
|
||||
c.typ = common.TxTypeExit
|
||||
default:
|
||||
@@ -493,22 +499,21 @@ func idxTokenIDToString(idx string, tid common.TokenID) string {
|
||||
func (p *parser) parse() (*parsedSet, error) {
|
||||
ps := &parsedSet{}
|
||||
i := 0 // lines will start counting at line 1
|
||||
accounts := make(map[string]bool)
|
||||
var setTypeOfSet setType
|
||||
users := make(map[string]bool)
|
||||
for {
|
||||
i++
|
||||
instruction, err := p.parseLine(setTypeOfSet)
|
||||
instruction, err := p.parseLine(ps.typ)
|
||||
if err == errof {
|
||||
break
|
||||
}
|
||||
if err == setTypeLine {
|
||||
if setTypeOfSet != "" {
|
||||
return ps, fmt.Errorf("Line %d: Instruction of 'Type: %s' when there is already a previous instruction 'Type: %s' defined", i, instruction.typ, setTypeOfSet)
|
||||
if ps.typ != "" {
|
||||
return ps, fmt.Errorf("Line %d: Instruction of 'Type: %s' when there is already a previous instruction 'Type: %s' defined", i, instruction.typ, ps.typ)
|
||||
}
|
||||
if instruction.typ == "PoolL2" {
|
||||
setTypeOfSet = setTypePoolL2
|
||||
ps.typ = setTypePoolL2
|
||||
} else if instruction.typ == "Blockchain" {
|
||||
setTypeOfSet = setTypeBlockchain
|
||||
ps.typ = setTypeBlockchain
|
||||
} else {
|
||||
log.Fatalf("Line %d: Invalid set type: '%s'. Valid set types: 'Blockchain', 'PoolL2'", i, instruction.typ)
|
||||
}
|
||||
@@ -528,18 +533,18 @@ func (p *parser) parse() (*parsedSet, error) {
|
||||
if err != nil {
|
||||
return ps, fmt.Errorf("Line %d: %s, err: %s", i, instruction.literal, err.Error())
|
||||
}
|
||||
if setTypeOfSet == "" {
|
||||
if ps.typ == "" {
|
||||
return ps, fmt.Errorf("Line %d: Set type not defined", i)
|
||||
}
|
||||
ps.instructions = append(ps.instructions, *instruction)
|
||||
accounts[instruction.from] = true
|
||||
if instruction.typ == common.TxTypeTransfer { // type: Transfer
|
||||
accounts[instruction.to] = true
|
||||
users[instruction.from] = true
|
||||
if instruction.typ == common.TxTypeTransfer || instruction.typ == common.TxTypeTransferToEthAddr || instruction.typ == common.TxTypeTransferToBJJ { // type: Transfer
|
||||
users[instruction.to] = true
|
||||
}
|
||||
}
|
||||
for a := range accounts {
|
||||
ps.accounts = append(ps.accounts, a)
|
||||
for u := range users {
|
||||
ps.users = append(ps.users, u)
|
||||
}
|
||||
sort.Strings(ps.accounts)
|
||||
sort.Strings(ps.users)
|
||||
return ps, nil
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func TestParseBlockchainTxs(t *testing.T) {
|
||||
instructions, err := parser.parse()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 25, len(instructions.instructions))
|
||||
assert.Equal(t, 7, len(instructions.accounts))
|
||||
assert.Equal(t, 7, len(instructions.users))
|
||||
|
||||
if debug {
|
||||
fmt.Println(instructions)
|
||||
@@ -94,7 +94,7 @@ func TestParsePoolTxs(t *testing.T) {
|
||||
instructions, err := parser.parse()
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 5, len(instructions.instructions))
|
||||
assert.Equal(t, 4, len(instructions.accounts))
|
||||
assert.Equal(t, 4, len(instructions.users))
|
||||
|
||||
if debug {
|
||||
fmt.Println(instructions)
|
||||
|
||||
@@ -176,4 +176,6 @@ PoolExit(1) A: 3
|
||||
PoolTransfer(1) A-B: 6 (1)
|
||||
PoolTransfer(1) B-C: 3 (1)
|
||||
PoolTransfer(1) A-C: 3 (1)
|
||||
PoolTransferToEthAddr(1) A-C: 3 (1)
|
||||
PoolTransferToBJJ(1) A-C: 3 (1)
|
||||
`
|
||||
|
||||
@@ -19,6 +19,6 @@ func TestCompileSets(t *testing.T) {
|
||||
tc := NewContext(eth.RollupConstMaxL1UserTx)
|
||||
_, err = tc.GenerateBlocks(SetBlockchain0)
|
||||
assert.Nil(t, err)
|
||||
_, err = tc.GenerateBlocks(SetPool0)
|
||||
_, err = tc.GeneratePoolL2Txs(SetPool0)
|
||||
assert.Nil(t, err)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import (
|
||||
// Context contains the data of the test
|
||||
type Context struct {
|
||||
Instructions []instruction
|
||||
accountsNames []string
|
||||
userNames []string
|
||||
Users map[string]*User
|
||||
lastRegisteredTokenID common.TokenID
|
||||
l1CreatedAccounts map[string]*Account
|
||||
@@ -98,18 +98,21 @@ type L2Tx struct {
|
||||
}
|
||||
|
||||
// GenerateBlocks returns an array of BlockData for a given set. It uses the
|
||||
// accounts (keys & nonces) of the Context.
|
||||
// users (keys & nonces) of the Context.
|
||||
func (tc *Context) GenerateBlocks(set string) ([]common.BlockData, error) {
|
||||
parser := newParser(strings.NewReader(set))
|
||||
parsedSet, err := parser.parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if parsedSet.typ != setTypeBlockchain {
|
||||
return nil, fmt.Errorf("Expected set type: %s, found: %s", setTypeBlockchain, parsedSet.typ)
|
||||
}
|
||||
|
||||
tc.Instructions = parsedSet.instructions
|
||||
tc.accountsNames = parsedSet.accounts
|
||||
tc.userNames = parsedSet.users
|
||||
|
||||
tc.generateKeys(tc.accountsNames)
|
||||
tc.generateKeys(tc.userNames)
|
||||
|
||||
var blocks []common.BlockData
|
||||
for _, inst := range parsedSet.instructions {
|
||||
@@ -418,39 +421,42 @@ func (tc *Context) checkIfTokenIsRegistered(inst instruction) error {
|
||||
}
|
||||
|
||||
// GeneratePoolL2Txs returns an array of common.PoolL2Tx from a given set. It
|
||||
// uses the accounts (keys & nonces) of the Context.
|
||||
// uses the users (keys) of the Context.
|
||||
func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
|
||||
parser := newParser(strings.NewReader(set))
|
||||
parsedSet, err := parser.parse()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if parsedSet.typ != setTypePoolL2 {
|
||||
return nil, fmt.Errorf("Expected set type: %s, found: %s", setTypePoolL2, parsedSet.typ)
|
||||
}
|
||||
|
||||
tc.Instructions = parsedSet.instructions
|
||||
tc.accountsNames = parsedSet.accounts
|
||||
tc.userNames = parsedSet.users
|
||||
|
||||
tc.generateKeys(tc.accountsNames)
|
||||
tc.generateKeys(tc.userNames)
|
||||
|
||||
txs := []common.PoolL2Tx{}
|
||||
for _, inst := range tc.Instructions {
|
||||
switch inst.typ {
|
||||
case common.TxTypeTransfer:
|
||||
case common.TxTypeTransfer, common.TxTypeTransferToEthAddr, common.TxTypeTransferToBJJ:
|
||||
if err := tc.checkIfAccountExists(inst.from, inst); err != nil {
|
||||
log.Error(err)
|
||||
return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
|
||||
}
|
||||
if inst.typ == common.TxTypeTransfer {
|
||||
// if TxTypeTransfer, need to exist the ToIdx account
|
||||
if err := tc.checkIfAccountExists(inst.to, inst); err != nil {
|
||||
log.Error(err)
|
||||
return nil, fmt.Errorf("Line %d: %s", inst.lineNum, err.Error())
|
||||
}
|
||||
}
|
||||
tc.Users[inst.from].Accounts[inst.tokenID].Nonce++
|
||||
// if account of receiver does not exist, don't use
|
||||
// ToIdx, and use only ToEthAddr & ToBJJ
|
||||
tx := common.PoolL2Tx{
|
||||
FromIdx: tc.Users[inst.from].Accounts[inst.tokenID].Idx,
|
||||
ToIdx: tc.Users[inst.to].Accounts[inst.tokenID].Idx,
|
||||
ToEthAddr: tc.Users[inst.to].Addr,
|
||||
ToBJJ: tc.Users[inst.to].BJJ.Public(),
|
||||
TokenID: inst.tokenID,
|
||||
Amount: big.NewInt(int64(inst.amount)),
|
||||
Fee: common.FeeSelector(inst.fee),
|
||||
@@ -459,7 +465,19 @@ func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
|
||||
Timestamp: time.Now(),
|
||||
RqToEthAddr: common.EmptyAddr,
|
||||
RqToBJJ: nil,
|
||||
Type: common.TxTypeTransfer,
|
||||
Type: inst.typ,
|
||||
}
|
||||
if tx.Type == common.TxTypeTransfer {
|
||||
tx.ToIdx = tc.Users[inst.to].Accounts[inst.tokenID].Idx
|
||||
tx.ToEthAddr = tc.Users[inst.to].Addr
|
||||
tx.ToBJJ = tc.Users[inst.to].BJJ.Public()
|
||||
} else if tx.Type == common.TxTypeTransferToEthAddr {
|
||||
tx.ToIdx = common.Idx(0)
|
||||
tx.ToEthAddr = tc.Users[inst.to].Addr
|
||||
} else if tx.Type == common.TxTypeTransferToBJJ {
|
||||
tx.ToIdx = common.Idx(0)
|
||||
tx.ToEthAddr = common.FFAddr
|
||||
tx.ToBJJ = tc.Users[inst.to].BJJ.Public()
|
||||
}
|
||||
nTx, err := common.NewPoolL2Tx(&tx)
|
||||
if err != nil {
|
||||
@@ -506,12 +524,12 @@ func (tc *Context) GeneratePoolL2Txs(set string) ([]common.PoolL2Tx, error) {
|
||||
return txs, nil
|
||||
}
|
||||
|
||||
// generateKeys generates BabyJubJub & Address keys for the given list of
|
||||
// account names in a deterministic way. This means, that for the same given
|
||||
// 'accNames' in a certain order, the keys will be always the same.
|
||||
func (tc *Context) generateKeys(accNames []string) {
|
||||
for i := 1; i < len(accNames)+1; i++ {
|
||||
if _, ok := tc.Users[accNames[i-1]]; ok {
|
||||
// generateKeys generates BabyJubJub & Address keys for the given list of user
|
||||
// names in a deterministic way. This means, that for the same given
|
||||
// 'userNames' in a certain order, the keys will be always the same.
|
||||
func (tc *Context) generateKeys(userNames []string) {
|
||||
for i := 1; i < len(userNames)+1; i++ {
|
||||
if _, ok := tc.Users[userNames[i-1]]; ok {
|
||||
// account already created
|
||||
continue
|
||||
}
|
||||
@@ -531,6 +549,6 @@ func (tc *Context) generateKeys(accNames []string) {
|
||||
Addr: addr,
|
||||
Accounts: make(map[common.TokenID]*Account),
|
||||
}
|
||||
tc.Users[accNames[i-1]] = &u
|
||||
tc.Users[userNames[i-1]] = &u
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +207,12 @@ func TestGeneratePoolL2Txs(t *testing.T) {
|
||||
PoolTransfer(3) User1-User0: 15 (1)
|
||||
PoolTransfer(2) B-D: 3 (1)
|
||||
PoolExit(1) A: 3
|
||||
PoolTransferToEthAddr(1) A-B: 1 (1)
|
||||
PoolTransferToBJJ(1) A-B: 1 (1)
|
||||
`
|
||||
poolL2Txs, err := tc.GeneratePoolL2Txs(set)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, 9, len(poolL2Txs))
|
||||
assert.Equal(t, 11, len(poolL2Txs))
|
||||
assert.Equal(t, common.TxTypeTransfer, poolL2Txs[0].Type)
|
||||
assert.Equal(t, common.TxTypeExit, poolL2Txs[8].Type)
|
||||
assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[0].ToEthAddr.Hex())
|
||||
@@ -222,6 +224,13 @@ func TestGeneratePoolL2Txs(t *testing.T) {
|
||||
assert.Equal(t, common.Nonce(2), poolL2Txs[3].Nonce)
|
||||
assert.Equal(t, common.Nonce(3), poolL2Txs[8].Nonce)
|
||||
|
||||
assert.Equal(t, tc.Users["B"].Addr.Hex(), poolL2Txs[9].ToEthAddr.Hex())
|
||||
assert.Nil(t, poolL2Txs[9].ToBJJ)
|
||||
assert.Equal(t, common.TxTypeTransferToEthAddr, poolL2Txs[9].Type)
|
||||
assert.Equal(t, common.FFAddr, poolL2Txs[10].ToEthAddr)
|
||||
assert.Equal(t, tc.Users["B"].BJJ.Public().String(), poolL2Txs[10].ToBJJ.String())
|
||||
assert.Equal(t, common.TxTypeTransferToBJJ, poolL2Txs[10].Type)
|
||||
|
||||
// load another set in the same Context
|
||||
set = `
|
||||
Type: PoolL2
|
||||
@@ -231,9 +240,37 @@ func TestGeneratePoolL2Txs(t *testing.T) {
|
||||
`
|
||||
poolL2Txs, err = tc.GeneratePoolL2Txs(set)
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, common.Nonce(4), poolL2Txs[0].Nonce)
|
||||
assert.Equal(t, common.Nonce(6), poolL2Txs[0].Nonce)
|
||||
assert.Equal(t, common.Nonce(2), poolL2Txs[1].Nonce)
|
||||
assert.Equal(t, common.Nonce(5), poolL2Txs[2].Nonce)
|
||||
assert.Equal(t, common.Nonce(7), poolL2Txs[2].Nonce)
|
||||
|
||||
// check that a PoolL2Tx can be done to a non existing ToIdx
|
||||
set = `
|
||||
Type: Blockchain
|
||||
AddToken(1)
|
||||
CreateAccountDeposit(1) A: 10
|
||||
> batchL1
|
||||
> batchL1
|
||||
> block
|
||||
`
|
||||
tc = NewContext(eth.RollupConstMaxL1UserTx)
|
||||
_, err = tc.GenerateBlocks(set)
|
||||
require.Nil(t, err)
|
||||
set = `
|
||||
Type: PoolL2
|
||||
PoolTransferToEthAddr(1) A-B: 3 (1)
|
||||
PoolTransferToBJJ(1) A-C: 3 (1)
|
||||
`
|
||||
_, err = tc.GeneratePoolL2Txs(set)
|
||||
require.Nil(t, err)
|
||||
// expect error, as FromIdx=B is still not created for TokenID=1
|
||||
set = `
|
||||
Type: PoolL2
|
||||
PoolTransferToEthAddr(1) B-A: 3 (1)
|
||||
PoolTransferToBJJ(1) B-A: 3 (1)
|
||||
`
|
||||
_, err = tc.GeneratePoolL2Txs(set)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestGenerateErrors(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user