Browse Source

Merge pull request #222 from hermeznetwork/feature/txtransfertoethaddrbjj

Add TxTypeTransferToEthAddr&ToBJJ to StateDB & Til
feature/sql-semaphore1
Eduard S 3 years ago
committed by GitHub
parent
commit
0cd7179f47
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 45 deletions
  1. +2
    -1
      db/statedb/txprocessors.go
  2. +21
    -16
      test/til/lang.go
  3. +2
    -2
      test/til/lang_test.go
  4. +2
    -0
      test/til/sets.go
  5. +1
    -1
      test/til/sets_test.go
  6. +40
    -22
      test/til/txs.go
  7. +40
    -3
      test/til/txs_test.go

+ 2
- 1
db/statedb/txprocessors.go

@ -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)

+ 21
- 16
test/til/lang.go

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

+ 2
- 2
test/til/lang_test.go

@ -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)

+ 2
- 0
test/til/sets.go

@ -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)
`

+ 1
- 1
test/til/sets_test.go

@ -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)
}

+ 40
- 22
test/til/txs.go

@ -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 err := tc.checkIfAccountExists(inst.to, 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
}
}

+ 40
- 3
test/til/txs_test.go

@ -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) {

Loading…
Cancel
Save