From 0ac6c0ecbb935d362a00557a7af052bbf072eb7d Mon Sep 17 00:00:00 2001 From: arnaucube Date: Thu, 22 Oct 2020 17:39:18 +0200 Subject: [PATCH] Add TxTypeTransferToEthAddr&ToBJJ to StateDB & Til Add TxTypeTransferToEthAddr&ToBJJ to StateDB & Til resolves #203, resolves #209 --- db/statedb/txprocessors.go | 3 +- test/til/lang.go | 37 +++++++++++++---------- test/til/lang_test.go | 4 +-- test/til/sets.go | 2 ++ test/til/sets_test.go | 2 +- test/til/txs.go | 62 ++++++++++++++++++++++++-------------- test/til/txs_test.go | 43 ++++++++++++++++++++++++-- 7 files changed, 108 insertions(+), 45 deletions(-) diff --git a/db/statedb/txprocessors.go b/db/statedb/txprocessors.go index c6270a5..2602a10 100644 --- a/db/statedb/txprocessors.go +++ b/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) diff --git a/test/til/lang.go b/test/til/lang.go index f5ebbcf..7f463db 100644 --- a/test/til/lang.go +++ b/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 } diff --git a/test/til/lang_test.go b/test/til/lang_test.go index ae57518..e22392b 100644 --- a/test/til/lang_test.go +++ b/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) diff --git a/test/til/sets.go b/test/til/sets.go index a3cba57..f32dd83 100644 --- a/test/til/sets.go +++ b/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) ` diff --git a/test/til/sets_test.go b/test/til/sets_test.go index 608f569..cad790b 100644 --- a/test/til/sets_test.go +++ b/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) } diff --git a/test/til/txs.go b/test/til/txs.go index a086d38..7862fee 100644 --- a/test/til/txs.go +++ b/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 } } diff --git a/test/til/txs_test.go b/test/til/txs_test.go index ff3f1d5..4feeaeb 100644 --- a/test/til/txs_test.go +++ b/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) {