diff options
-rw-r--r-- | core/vm/oracle_contracts.go | 9 | ||||
-rw-r--r-- | dex/app.go | 11 | ||||
-rw-r--r-- | dex/app_test.go | 722 |
3 files changed, 19 insertions, 723 deletions
diff --git a/core/vm/oracle_contracts.go b/core/vm/oracle_contracts.go index 1ebf3f1d4..cf060e9ac 100644 --- a/core/vm/oracle_contracts.go +++ b/core/vm/oracle_contracts.go @@ -488,6 +488,15 @@ func (s *GovernanceState) PutNodeOffsets(n *nodeInfo, offset *big.Int) error { return nil } +func (s *GovernanceState) GetNodeOwnerByID(id coreTypes.NodeID) (common.Address, error) { + offset := s.NodesOffsetByNodeKeyAddress(idToAddress(id)) + if offset.Cmp(big.NewInt(0)) < 0 { + return common.Address{}, errors.New("node not found") + } + node := s.Node(offset) + return node.Owner, nil +} + // struct Delegator { // address node; // address owner; diff --git a/dex/app.go b/dex/app.go index 6ef20684f..e7fdbb4fe 100644 --- a/dex/app.go +++ b/dex/app.go @@ -488,10 +488,19 @@ func (d *DexconApp) BlockDelivered( panic(err) } + var owner common.Address + if !block.IsEmpty() { + gs := d.gov.GetStateForConfigAtRound(block.Position.Round) + owner, err = gs.GetNodeOwnerByID(block.ProposerID) + if err != nil { + panic(err) + } + } + newBlock := types.NewBlock(&types.Header{ Number: new(big.Int).SetUint64(result.Height), Time: big.NewInt(result.Timestamp.UnixNano() / 1000000), - Coinbase: common.BytesToAddress(block.ProposerID.Bytes()), + Coinbase: owner, GasLimit: d.gov.DexconConfiguration(block.Position.Round).BlockGasLimit, Difficulty: big.NewInt(1), Round: block.Position.Round, diff --git a/dex/app_test.go b/dex/app_test.go deleted file mode 100644 index 221c55e0d..000000000 --- a/dex/app_test.go +++ /dev/null @@ -1,722 +0,0 @@ -package dex - -import ( - "crypto/ecdsa" - "fmt" - "math/big" - "testing" - "time" - - coreCommon "github.com/dexon-foundation/dexon-consensus/common" - coreTypes "github.com/dexon-foundation/dexon-consensus/core/types" - - "github.com/dexon-foundation/dexon/common" - "github.com/dexon-foundation/dexon/consensus/dexcon" - "github.com/dexon-foundation/dexon/core" - "github.com/dexon-foundation/dexon/core/types" - "github.com/dexon-foundation/dexon/core/vm" - "github.com/dexon-foundation/dexon/crypto" - "github.com/dexon-foundation/dexon/ethdb" - "github.com/dexon-foundation/dexon/params" - "github.com/dexon-foundation/dexon/rlp" -) - -func TestPreparePayload(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("hex to ecdsa error: %v", err) - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - t.Fatalf("new test dexon error: %v", err) - } - - signer := types.NewEIP155Signer(dex.chainConfig.ChainID) - - var expectTx types.Transactions - for i := 0; i < 5; i++ { - tx, err := addTx(dex, i, signer, key) - if err != nil { - t.Fatalf("add tx error: %v", err) - } - expectTx = append(expectTx, tx) - } - - // This transaction will not be included. - _, err = addTx(dex, 100, signer, key) - if err != nil { - t.Fatalf("add tx error: %v", err) - } - - chainNum := uint32(0) - root := dex.blockchain.CurrentBlock().Root() - dex.app.chainRoot.Store(chainNum, &root) - payload, err := dex.app.PreparePayload(coreTypes.Position{}) - if err != nil { - t.Fatalf("prepare payload error: %v", err) - } - - var transactions types.Transactions - err = rlp.DecodeBytes(payload, &transactions) - if err != nil { - t.Fatalf("rlp decode error: %v", err) - } - - // Only one chain id allow prepare transactions. - if len(transactions) != 5 { - t.Fatalf("incorrect transaction num expect %v but %v", 5, len(transactions)) - } - - for i, tx := range transactions { - if expectTx[i].Gas() != tx.Gas() { - t.Fatalf("unexpected gas expect %v but %v", expectTx[i].Gas(), tx.Gas()) - } - - if expectTx[i].Hash() != tx.Hash() { - t.Fatalf("unexpected hash expect %v but %v", expectTx[i].Hash(), tx.Hash()) - } - - if expectTx[i].Nonce() != tx.Nonce() { - t.Fatalf("unexpected nonce expect %v but %v", expectTx[i].Nonce(), tx.Nonce()) - } - - if expectTx[i].GasPrice().Uint64() != tx.GasPrice().Uint64() { - t.Fatalf("unexpected gas price expect %v but %v", - expectTx[i].GasPrice().Uint64(), tx.GasPrice().Uint64()) - } - } -} - -func TestPrepareWitness(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("hex to ecdsa error: %v", err) - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - t.Fatalf("new test dexon error: %v", err) - } - - currentBlock := dex.blockchain.CurrentBlock() - - witness, err := dex.app.PrepareWitness(0) - if err != nil { - t.Fatalf("prepare witness error: %v", err) - } - - if witness.Height != currentBlock.NumberU64() { - t.Fatalf("unexpeted witness height %v", witness.Height) - } - - var witnessBlockHash common.Hash - err = rlp.DecodeBytes(witness.Data, &witnessBlockHash) - if err != nil { - t.Fatalf("rlp decode error: %v", err) - } - - if witnessBlockHash != currentBlock.Hash() { - t.Fatalf("expect root %v but %v", currentBlock.Hash(), witnessBlockHash) - } - - if _, err := dex.app.PrepareWitness(999); err == nil { - t.Fatalf("it must be get error from prepare") - } else { - t.Logf("Nice error: %v", err) - } -} - -func TestVerifyBlock(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("hex to ecdsa error: %v", err) - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - t.Fatalf("new test dexon error: %v", err) - } - - chainID := big.NewInt(0) - - root := dex.blockchain.CurrentBlock().Root() - dex.app.chainRoot.Store(uint32(chainID.Uint64()), &root) - - // Prepare first confirmed block. - _, err = prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 0) - if err != nil { - t.Fatalf("prepare confirmed blocks error: %v", err) - } - - // Prepare normal block. - block := &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 100) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - // Expect ok. - status := dex.app.VerifyBlock(block) - if status != coreTypes.VerifyOK { - t.Fatalf("verify fail: %v", status) - } - - // Prepare invalid nonce tx. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 1, 100) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - // Expect invalid block. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail: %v", status) - } - - // Prepare invalid block height. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 2 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 100) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - // Expect retry later. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyRetryLater { - t.Fatalf("verify fail expect retry later but get %v", status) - } - - // Prepare reach block limit. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - block.Payload, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 10000) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - // Expect invalid block. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail expect invalid block but get %v", status) - } - - // Prepare insufficient funds. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - signer := types.NewEIP155Signer(dex.chainConfig.ChainID) - tx := types.NewTransaction( - 0, - common.BytesToAddress([]byte{9}), - big.NewInt(50000000000000001), - params.TxGas, - big.NewInt(10), - nil) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - - block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx}) - if err != nil { - return - } - - // expect invalid block - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail expect invalid block but get %v", status) - } - - // Prepare invalid intrinsic gas. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - signer = types.NewEIP155Signer(dex.chainConfig.ChainID) - tx = types.NewTransaction( - 0, - common.BytesToAddress([]byte{9}), - big.NewInt(1), - params.TxGas, - big.NewInt(10), - make([]byte, 1)) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - - block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx}) - if err != nil { - return - } - - // Expect invalid block. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail expect invalid block but get %v", status) - } - - // Prepare invalid transactions with nonce. - block = &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Position.Height = 1 - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - _, block.Witness, err = prepareDataWithoutTxPool(dex, key, 0, 0) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - - signer = types.NewEIP155Signer(dex.chainConfig.ChainID) - tx1 := types.NewTransaction( - 0, - common.BytesToAddress([]byte{9}), - big.NewInt(1), - params.TxGas, - big.NewInt(10), - make([]byte, 1)) - tx1, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - - // Invalid nonce. - tx2 := types.NewTransaction( - 2, - common.BytesToAddress([]byte{9}), - big.NewInt(1), - params.TxGas, - big.NewInt(10), - make([]byte, 1)) - tx2, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - - block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx1, tx2}) - if err != nil { - return - } - - // Expect invalid block. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail expect invalid block but get %v", status) - } - - // Invalid gas price. - tx = types.NewTransaction( - 0, - common.BytesToAddress([]byte{9}), - big.NewInt(1), - params.TxGas, - big.NewInt(5), - make([]byte, 1)) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - block.Payload, err = rlp.EncodeToBytes(types.Transactions{tx}) - if err != nil { - return - } - - // Expect invalid block. - status = dex.app.VerifyBlock(block) - if status != coreTypes.VerifyInvalidBlock { - t.Fatalf("verify fail expect invalid block but get %v", status) - } - -} - -func TestBlockConfirmed(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("hex to ecdsa error: %v", err) - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - t.Fatalf("new test dexon error: %v", err) - } - - chainID := big.NewInt(0) - - root := dex.blockchain.CurrentBlock().Root() - dex.app.chainRoot.Store(uint32(chainID.Uint64()), &root) - - var ( - expectCost big.Int - expectNonce uint64 - expectCounter uint64 - ) - for i := 0; i < 10; i++ { - var startNonce int - if expectNonce != 0 { - startNonce = int(expectNonce) + 1 - } - payload, witness, cost, nonce, err := prepareData(dex, key, startNonce, 50) - if err != nil { - t.Fatalf("prepare data error: %v", err) - } - expectCost.Add(&expectCost, &cost) - expectNonce = nonce - - block := &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Witness = witness - block.Payload = payload - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - - dex.app.BlockConfirmed(*block) - expectCounter++ - } - - info := dex.app.blockchain.GetAddressInfo(uint32(chainID.Uint64()), - crypto.PubkeyToAddress(key.PublicKey)) - - if info.Counter != expectCounter { - t.Fatalf("expect address counter is %v but %v", expectCounter, info.Counter) - } - - if info.Cost.Cmp(&expectCost) != 0 { - t.Fatalf("expect address cost is %v but %v", expectCost.Uint64(), info.Cost.Uint64()) - } - - if info.Nonce != expectNonce { - t.Fatalf("expect address nonce is %v but %v", expectNonce, info.Nonce) - } -} - -func TestBlockDelivered(t *testing.T) { - key, err := crypto.GenerateKey() - if err != nil { - t.Fatalf("hex to ecdsa error: %v", err) - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - t.Fatalf("new test dexon error: %v", err) - } - - chainID := big.NewInt(0) - - root := dex.blockchain.CurrentBlock().Root() - dex.app.chainRoot.Store(uint32(chainID.Uint64()), &root) - - address := crypto.PubkeyToAddress(key.PublicKey) - firstBlocksInfo, err := prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 50) - if err != nil { - t.Fatalf("preapare confirmed block error: %v", err) - } - - dex.app.BlockDelivered(firstBlocksInfo[0].Block.Hash, firstBlocksInfo[0].Block.Position, - coreTypes.FinalizationResult{ - Timestamp: time.Now(), - Height: 1, - }) - - currentState, err := dex.blockchain.State() - if err != nil { - t.Fatalf("get state error: %v", err) - } - currentBlock := dex.blockchain.CurrentBlock() - if currentBlock.NumberU64() != 1 { - t.Fatalf("unexpected current block number %v", currentBlock.NumberU64()) - } - - currentNonce := currentState.GetNonce(address) - if currentNonce != firstBlocksInfo[0].Nonce+1 { - t.Fatalf("unexpected pending state nonce %v", currentNonce) - } - - balance := currentState.GetBalance(address) - if new(big.Int).Add(balance, &firstBlocksInfo[0].Cost).Cmp(big.NewInt(50000000000000000)) != 0 { - t.Fatalf("unexpected pending state balance %v", balance) - } -} - -func BenchmarkBlockDeliveredFlow(b *testing.B) { - key, err := crypto.GenerateKey() - if err != nil { - b.Fatalf("hex to ecdsa error: %v", err) - return - } - - dex, err := newTestDexonWithGenesis(key) - if err != nil { - b.Fatalf("new test dexon error: %v", err) - } - - b.ResetTimer() - for i := 1; i <= b.N; i++ { - blocksInfo, err := prepareConfirmedBlocks(dex, []*ecdsa.PrivateKey{key}, 100) - if err != nil { - b.Fatalf("preapare confirmed block error: %v", err) - return - } - - dex.app.BlockDelivered(blocksInfo[0].Block.Hash, blocksInfo[0].Block.Position, - coreTypes.FinalizationResult{ - Timestamp: time.Now(), - Height: uint64(i), - }) - } -} - -func newTestDexonWithGenesis(allocKey *ecdsa.PrivateKey) (*Dexon, error) { - db := ethdb.NewMemDatabase() - - key, err := crypto.GenerateKey() - if err != nil { - panic(err) - } - - testBankAddress := crypto.PubkeyToAddress(allocKey.PublicKey) - genesis := core.DefaultTestnetGenesisBlock() - genesis.Alloc = core.GenesisAlloc{ - testBankAddress: { - Balance: big.NewInt(100000000000000000), - Staked: big.NewInt(50000000000000000), - PublicKey: crypto.FromECDSAPub(&key.PublicKey), - }, - } - genesis.Config.Dexcon.MinGasPrice = big.NewInt(10) - chainConfig, _, err := core.SetupGenesisBlock(db, genesis) - if err != nil { - return nil, err - } - - config := Config{PrivateKey: key} - vmConfig := vm.Config{IsBlockProposer: true} - - engine := dexcon.New() - - dex := &Dexon{ - chainDb: db, - chainConfig: chainConfig, - networkID: config.NetworkId, - engine: engine, - } - - dex.blockchain, err = core.NewBlockChain(db, nil, chainConfig, engine, vmConfig, nil) - if err != nil { - return nil, err - } - - txPoolConfig := core.DefaultTxPoolConfig - dex.txPool = core.NewTxPool(txPoolConfig, chainConfig, dex.blockchain, true) - - dex.APIBackend = &DexAPIBackend{dex, nil} - dex.governance = NewDexconGovernance(dex.APIBackend, dex.chainConfig, config.PrivateKey) - engine.SetGovStateFetcher(dex.governance) - dex.app = NewDexconApp(dex.txPool, dex.blockchain, dex.governance, db, &config) - - return dex, nil -} - -// Add tx into tx pool. -func addTx(dex *Dexon, nonce int, signer types.Signer, key *ecdsa.PrivateKey) ( - *types.Transaction, error) { - tx := types.NewTransaction( - uint64(nonce), - common.BytesToAddress([]byte{9}), - big.NewInt(int64(nonce*1)), - params.TxGas, - big.NewInt(10), - nil) - tx, err := types.SignTx(tx, signer, key) - if err != nil { - return nil, err - } - - if err := dex.txPool.AddRemote(tx); err != nil { - return nil, err - } - - return tx, nil -} - -// Prepare data with given transaction number and start nonce. -func prepareData(dex *Dexon, key *ecdsa.PrivateKey, startNonce, txNum int) ( - payload []byte, witness coreTypes.Witness, cost big.Int, nonce uint64, err error) { - signer := types.NewEIP155Signer(dex.chainConfig.ChainID) - - for n := startNonce; n < startNonce+txNum; n++ { - var tx *types.Transaction - tx, err = addTx(dex, n, signer, key) - if err != nil { - return - } - - cost.Add(&cost, tx.Cost()) - nonce = uint64(n) - } - - payload, err = dex.app.PreparePayload(coreTypes.Position{}) - if err != nil { - return - } - - witness, err = dex.app.PrepareWitness(0) - if err != nil { - return - } - - return -} - -func prepareConfirmedBlockWithTxAndData(dex *Dexon, key *ecdsa.PrivateKey, data [][]byte, round uint64) ( - Block *coreTypes.Block, err error) { - address := crypto.PubkeyToAddress(key.PublicKey) - - for _, d := range data { - // Prepare one block for pending. - nonce := dex.txPool.State().GetNonce(address) - signer := types.NewEIP155Signer(dex.chainConfig.ChainID) - tx := types.NewTransaction(uint64(nonce), vm.GovernanceContractAddress, big.NewInt(0), params.TxGas*2, - big.NewInt(1), d) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return nil, err - } - - dex.txPool.AddRemote(tx) - if err != nil { - return nil, err - } - } - var ( - payload []byte - witness coreTypes.Witness - ) - - payload, err = dex.app.PreparePayload(coreTypes.Position{Round: round}) - if err != nil { - return - } - - witness, err = dex.app.PrepareWitness(0) - if err != nil { - return nil, err - } - - block := &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Witness = witness - block.Payload = payload - block.Position.Round = round - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - - status := dex.app.VerifyBlock(block) - if status != coreTypes.VerifyOK { - err = fmt.Errorf("verify fail: %v", status) - return nil, err - } - - dex.app.BlockConfirmed(*block) - return block, nil -} - -func prepareDataWithoutTxPool(dex *Dexon, key *ecdsa.PrivateKey, startNonce, txNum int) ( - payload []byte, witness coreTypes.Witness, err error) { - signer := types.NewEIP155Signer(dex.chainConfig.ChainID) - - var transactions types.Transactions - for n := startNonce; n < startNonce+txNum; n++ { - tx := types.NewTransaction( - uint64(n), - common.BytesToAddress([]byte{9}), - big.NewInt(int64(n*1)), - params.TxGas, - big.NewInt(10), - nil) - tx, err = types.SignTx(tx, signer, key) - if err != nil { - return - } - transactions = append(transactions, tx) - } - - payload, err = rlp.EncodeToBytes(&transactions) - if err != nil { - return - } - - witness, err = dex.app.PrepareWitness(0) - if err != nil { - return - } - - return -} - -func prepareConfirmedBlocks(dex *Dexon, keys []*ecdsa.PrivateKey, txNum int) (blocksInfo []struct { - Block *coreTypes.Block - Cost big.Int - Nonce uint64 -}, err error) { - for _, key := range keys { - address := crypto.PubkeyToAddress(key.PublicKey) - - // Prepare one block for pending. - var ( - payload []byte - witness coreTypes.Witness - cost big.Int - nonce uint64 - ) - startNonce := dex.txPool.State().GetNonce(address) - payload, witness, cost, nonce, err = prepareData(dex, key, int(startNonce), txNum) - if err != nil { - err = fmt.Errorf("prepare data error: %v", err) - return - } - - block := &coreTypes.Block{} - block.Hash = coreCommon.NewRandomHash() - block.Witness = witness - block.Payload = payload - block.ProposerID = coreTypes.NodeID{coreCommon.Hash{1, 2, 3}} - - status := dex.app.VerifyBlock(block) - if status != coreTypes.VerifyOK { - err = fmt.Errorf("verify fail: %v", status) - return - } - - dex.app.BlockConfirmed(*block) - - blocksInfo = append(blocksInfo, struct { - Block *coreTypes.Block - Cost big.Int - Nonce uint64 - }{Block: block, Cost: cost, Nonce: nonce}) - } - - return -} |