Merge pull request #453: Core/State Unit Tests

This commit is contained in:
Aleksandr Bezobchuk
2018-07-26 09:36:07 -04:00
parent 024325e981
commit 0cebfeb759
13 changed files with 931 additions and 86 deletions
+19 -17
View File
@@ -3,8 +3,8 @@ package core
import (
"math/big"
ethcommon "github.com/ethereum/go-ethereum/common"
ethconsensus "github.com/ethereum/go-ethereum/consensus"
ethcmn "github.com/ethereum/go-ethereum/common"
ethcons "github.com/ethereum/go-ethereum/consensus"
ethstate "github.com/ethereum/go-ethereum/core/state"
ethtypes "github.com/ethereum/go-ethereum/core/types"
ethrpc "github.com/ethereum/go-ethereum/rpc"
@@ -20,7 +20,7 @@ import (
// NOTE: Ethermint will distribute the fees out to validators, so the structure
// and functionality of this is a WIP and subject to change.
type ChainContext struct {
Coinbase ethcommon.Address
Coinbase ethcmn.Address
headersByNumber map[uint64]*ethtypes.Header
}
@@ -32,23 +32,25 @@ func NewChainContext() *ChainContext {
// Engine implements Ethereum's core.ChainContext interface. As a ChainContext
// implements the consensus.Engine interface, it is simply returned.
func (cc *ChainContext) Engine() ethconsensus.Engine {
func (cc *ChainContext) Engine() ethcons.Engine {
return cc
}
// SetHeader implements Ethereum's core.ChainContext interface. It sets the
// header for the given block number.
func (cc *ChainContext) SetHeader(number uint64, header *ethtypes.Header) {
cc.headersByNumber[number] = header
}
// GetHeader implements Ethereum's core.ChainContext interface. It currently
// performs a no-op.
// GetHeader implements Ethereum's core.ChainContext interface.
//
// TODO: The Cosmos SDK supports retreiving such information in contexts and
// multi-store, so this will be need to be integrated.
func (cc *ChainContext) GetHeader(parentHash ethcommon.Hash, number uint64) *ethtypes.Header {
func (cc *ChainContext) GetHeader(_ ethcmn.Hash, number uint64) *ethtypes.Header {
if header, ok := cc.headersByNumber[number]; ok {
return header
}
return nil
}
@@ -58,7 +60,7 @@ func (cc *ChainContext) GetHeader(parentHash ethcommon.Hash, number uint64) *eth
//
// NOTE: Ethermint will distribute the fees out to validators, so the structure
// and functionality of this is a WIP and subject to change.
func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcommon.Address, error) {
func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcmn.Address, error) {
return cc.Coinbase, nil
}
@@ -67,13 +69,13 @@ func (cc *ChainContext) Author(_ *ethtypes.Header) (ethcommon.Address, error) {
//
// TODO: Do we need to support such RPC APIs? This will tie into a bigger
// discussion on if we want to support web3.
func (cc *ChainContext) APIs(_ ethconsensus.ChainReader) []ethrpc.API {
func (cc *ChainContext) APIs(_ ethcons.ChainReader) []ethrpc.API {
return nil
}
// CalcDifficulty implements Ethereum's core.ChainContext interface. It
// currently performs a no-op.
func (cc *ChainContext) CalcDifficulty(_ ethconsensus.ChainReader, _ uint64, _ *ethtypes.Header) *big.Int {
func (cc *ChainContext) CalcDifficulty(_ ethcons.ChainReader, _ uint64, _ *ethtypes.Header) *big.Int {
return nil
}
@@ -82,7 +84,7 @@ func (cc *ChainContext) CalcDifficulty(_ ethconsensus.ChainReader, _ uint64, _ *
//
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
func (cc *ChainContext) Finalize(
_ ethconsensus.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB,
_ ethcons.ChainReader, _ *ethtypes.Header, _ *ethstate.StateDB,
_ []*ethtypes.Transaction, _ []*ethtypes.Header, _ []*ethtypes.Receipt,
) (*ethtypes.Block, error) {
return nil, nil
@@ -92,7 +94,7 @@ func (cc *ChainContext) Finalize(
// performs a no-op.
//
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
func (cc *ChainContext) Prepare(_ ethconsensus.ChainReader, _ *ethtypes.Header) error {
func (cc *ChainContext) Prepare(_ ethcons.ChainReader, _ *ethtypes.Header) error {
return nil
}
@@ -100,7 +102,7 @@ func (cc *ChainContext) Prepare(_ ethconsensus.ChainReader, _ *ethtypes.Header)
// performs a no-op.
//
// TODO: Figure out if this needs to be hooked up to any part of the ABCI?
func (cc *ChainContext) Seal(_ ethconsensus.ChainReader, _ *ethtypes.Block, _ <-chan struct{}) (*ethtypes.Block, error) {
func (cc *ChainContext) Seal(_ ethcons.ChainReader, _ *ethtypes.Block, _ <-chan struct{}) (*ethtypes.Block, error) {
return nil, nil
}
@@ -109,7 +111,7 @@ func (cc *ChainContext) Seal(_ ethconsensus.ChainReader, _ *ethtypes.Block, _ <-
//
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers?
func (cc *ChainContext) VerifyHeader(_ ethconsensus.ChainReader, _ *ethtypes.Header, _ bool) error {
func (cc *ChainContext) VerifyHeader(_ ethcons.ChainReader, _ *ethtypes.Header, _ bool) error {
return nil
}
@@ -118,7 +120,7 @@ func (cc *ChainContext) VerifyHeader(_ ethconsensus.ChainReader, _ *ethtypes.Hea
//
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers?
func (cc *ChainContext) VerifyHeaders(_ ethconsensus.ChainReader, _ []*ethtypes.Header, _ []bool) (chan<- struct{}, <-chan error) {
func (cc *ChainContext) VerifyHeaders(_ ethcons.ChainReader, _ []*ethtypes.Header, _ []bool) (chan<- struct{}, <-chan error) {
return nil, nil
}
@@ -127,12 +129,12 @@ func (cc *ChainContext) VerifyHeaders(_ ethconsensus.ChainReader, _ []*ethtypes.
//
// TODO: Figure out if this needs to be hooked up to any part of the Cosmos SDK
// handlers?
func (cc *ChainContext) VerifySeal(_ ethconsensus.ChainReader, _ *ethtypes.Header) error {
func (cc *ChainContext) VerifySeal(_ ethcons.ChainReader, _ *ethtypes.Header) error {
return nil
}
// VerifyUncles implements Ethereum's core.ChainContext interface. It currently
// performs a no-op.
func (cc *ChainContext) VerifyUncles(_ ethconsensus.ChainReader, _ *ethtypes.Block) error {
func (cc *ChainContext) VerifyUncles(_ ethcons.ChainReader, _ *ethtypes.Block) error {
return nil
}
+121
View File
@@ -0,0 +1,121 @@
package core
// NOTE: A bulk of these unit tests will change and evolve as the context and
// implementation of ChainConext evolves.
import (
"math/big"
"testing"
ethcmn "github.com/ethereum/go-ethereum/common"
ethcons "github.com/ethereum/go-ethereum/consensus"
ethcore "github.com/ethereum/go-ethereum/core"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/stretchr/testify/require"
)
func TestChainContextInterface(t *testing.T) {
require.Implements(t, (*ethcore.ChainContext)(nil), new(ChainContext))
require.Implements(t, (*ethcons.Engine)(nil), new(ChainContext))
}
func TestNewChainContext(t *testing.T) {
cc := NewChainContext()
require.NotNil(t, cc.headersByNumber)
}
func TestChainContextEngine(t *testing.T) {
cc := NewChainContext()
require.Equal(t, cc, cc.Engine())
}
func TestChainContextSetHeader(t *testing.T) {
cc := NewChainContext()
header := &ethtypes.Header{
Number: big.NewInt(64),
}
cc.SetHeader(uint64(header.Number.Int64()), header)
require.Equal(t, header, cc.headersByNumber[uint64(header.Number.Int64())])
}
func TestChainContextGetHeader(t *testing.T) {
cc := NewChainContext()
header := &ethtypes.Header{
Number: big.NewInt(64),
}
cc.SetHeader(uint64(header.Number.Int64()), header)
require.Equal(t, header, cc.GetHeader(ethcmn.Hash{}, uint64(header.Number.Int64())))
require.Nil(t, cc.GetHeader(ethcmn.Hash{}, 0))
}
func TestChainContextAuthor(t *testing.T) {
cc := NewChainContext()
cb, err := cc.Author(nil)
require.Nil(t, err)
require.Equal(t, cc.Coinbase, cb)
}
func TestChainContextAPIs(t *testing.T) {
cc := NewChainContext()
require.Nil(t, cc.APIs(nil))
}
func TestChainContextCalcDifficulty(t *testing.T) {
cc := NewChainContext()
require.Nil(t, cc.CalcDifficulty(nil, 0, nil))
}
func TestChainContextFinalize(t *testing.T) {
cc := NewChainContext()
block, err := cc.Finalize(nil, nil, nil, nil, nil, nil)
require.Nil(t, err)
require.Nil(t, block)
}
func TestChainContextPrepare(t *testing.T) {
cc := NewChainContext()
err := cc.Prepare(nil, nil)
require.Nil(t, err)
}
func TestChainContextSeal(t *testing.T) {
cc := NewChainContext()
block, err := cc.Seal(nil, nil, nil)
require.Nil(t, err)
require.Nil(t, block)
}
func TestChainContextVerifyHeader(t *testing.T) {
cc := NewChainContext()
err := cc.VerifyHeader(nil, nil, false)
require.Nil(t, err)
}
func TestChainContextVerifyHeaders(t *testing.T) {
cc := NewChainContext()
ch, err := cc.VerifyHeaders(nil, nil, []bool{false})
require.Nil(t, err)
require.Nil(t, ch)
}
func TestChainContextVerifySeal(t *testing.T) {
cc := NewChainContext()
err := cc.VerifySeal(nil, nil)
require.Nil(t, err)
}
func TestChainContextVerifyUncles(t *testing.T) {
cc := NewChainContext()
err := cc.VerifyUncles(nil, nil)
require.Nil(t, err)
}
+147
View File
@@ -0,0 +1,147 @@
package core
// NOTE: A bulk of these unit tests will change and evolve as the context and
// implementation of ChainConext evolves.
import (
"fmt"
"testing"
ethdb "github.com/ethereum/go-ethereum/ethdb"
"github.com/stretchr/testify/require"
dbm "github.com/tendermint/tendermint/libs/db"
)
type (
kvPair struct {
key, value []byte
}
)
func newEthereumDB() *EthereumDB {
memDB := dbm.NewMemDB()
return &EthereumDB{CodeDB: memDB}
}
func TestEthereumDBInterface(t *testing.T) {
require.Implements(t, (*ethdb.Database)(nil), new(EthereumDB))
require.Implements(t, (*ethdb.Batch)(nil), new(EthereumDB))
}
func TestEthereumDBGet(t *testing.T) {
testEDB := newEthereumDB()
testCases := []struct {
edb *EthereumDB
data *kvPair
key []byte
expectedValue []byte
}{
{
edb: testEDB,
key: []byte("foo"),
expectedValue: nil,
},
{
edb: testEDB,
data: &kvPair{[]byte("foo"), []byte("bar")},
key: []byte("foo"),
expectedValue: []byte("bar"),
},
}
for i, tc := range testCases {
if tc.data != nil {
tc.edb.Put(tc.data.key, tc.data.value)
}
value, err := tc.edb.Get(tc.key)
require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i))
require.Equal(t, tc.expectedValue, value, fmt.Sprintf("unexpected result: test case #%d", i))
}
}
func TestEthereumDBHas(t *testing.T) {
testEDB := newEthereumDB()
testCases := []struct {
edb *EthereumDB
data *kvPair
key []byte
expectedValue bool
}{
{
edb: testEDB,
key: []byte("foo"),
expectedValue: false,
},
{
edb: testEDB,
data: &kvPair{[]byte("foo"), []byte("bar")},
key: []byte("foo"),
expectedValue: true,
},
}
for i, tc := range testCases {
if tc.data != nil {
tc.edb.Put(tc.data.key, tc.data.value)
}
ok, err := tc.edb.Has(tc.key)
require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i))
require.Equal(t, tc.expectedValue, ok, fmt.Sprintf("unexpected result: test case #%d", i))
}
}
func TestEthereumDBDelete(t *testing.T) {
testEDB := newEthereumDB()
testCases := []struct {
edb *EthereumDB
data *kvPair
key []byte
}{
{
edb: testEDB,
key: []byte("foo"),
},
{
edb: testEDB,
data: &kvPair{[]byte("foo"), []byte("bar")},
key: []byte("foo"),
},
}
for i, tc := range testCases {
if tc.data != nil {
tc.edb.Put(tc.data.key, tc.data.value)
}
err := tc.edb.Delete(tc.key)
ok, _ := tc.edb.Has(tc.key)
require.Nil(t, err, fmt.Sprintf("unexpected error: test case #%d", i))
require.False(t, ok, fmt.Sprintf("unexpected existence of key: test case #%d", i))
}
}
func TestEthereumDBNewBatch(t *testing.T) {
edb := newEthereumDB()
batch := edb.NewBatch()
require.Equal(t, edb, batch)
}
func TestEthereumDBValueSize(t *testing.T) {
edb := newEthereumDB()
size := edb.ValueSize()
require.Equal(t, 0, size)
}
func TestEthereumDBWrite(t *testing.T) {
edb := newEthereumDB()
err := edb.Write()
require.Nil(t, err)
}