Skip to content
This repository has been archived by the owner on Jun 9, 2024. It is now read-only.

refactor(blockchain): Minor cleanup and add safety checks. #1266

Merged
merged 16 commits into from
Nov 1, 2023
36 changes: 32 additions & 4 deletions cosmos/miner/miner.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/miner"

evmkeeper "pkg.berachain.dev/polaris/cosmos/x/evm/keeper"
"pkg.berachain.dev/polaris/eth"
"pkg.berachain.dev/polaris/eth/core/types"
)
Expand All @@ -45,17 +46,32 @@ type EnvelopeSerializer interface {
ToSdkTxBytes(*engine.ExecutionPayloadEnvelope, uint64) ([]byte, error)
}

type App interface {
BeginBlocker(ctx sdk.Context) (sdk.BeginBlock, error)
}

// EVMKeeper is an interface that defines the methods needed for the EVM setup.
type EVMKeeper interface {
// Setup initializes the EVM keeper.
Setup(evmkeeper.Blockchain) error
PrepareCheckState(context.Context) error
}

// Miner implements the baseapp.TxSelector interface.
type Miner struct {
eth.Miner
app App
keeper EVMKeeper
serializer EnvelopeSerializer
currentPayload *miner.Payload
}

// New produces a cosmos miner from a geth miner.
func New(gm eth.Miner) *Miner {
func New(gm eth.Miner, app App, keeper EVMKeeper) *Miner {
return &Miner{
Miner: gm,
Miner: gm,
keeper: keeper,
app: app,
}
}

Expand All @@ -68,8 +84,20 @@ func (m *Miner) Init(serializer EnvelopeSerializer) {
func (m *Miner) PrepareProposal(
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexanderbez is this safe?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't dug into the specifics of each individual method call, but since PrepareProposal state is discarded upon round timeout, any state modifications should be safe assuming you use the provided ctx (which it looks like you are!).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you'd like, I can dive into the individual method calls for further analysis.

ctx sdk.Context, _ *abci.RequestPrepareProposal,
) (*abci.ResponsePrepareProposal, error) {
var payloadEnvelopeBz []byte
var err error
var (
payloadEnvelopeBz []byte
err error
)

if err = m.keeper.PrepareCheckState(ctx); err != nil {
return nil, err
}
// We have to run the BeginBlocker to get the chain into the state it'll
// be in when the EVM transaction actually runs.
if _, err = m.app.BeginBlocker(ctx); err != nil {
return nil, err
}

if payloadEnvelopeBz, err = m.buildBlock(ctx); err != nil {
return nil, err
}
Expand Down
11 changes: 7 additions & 4 deletions cosmos/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package runtime

import (
"context"
"time"

"cosmossdk.io/log"
Expand Down Expand Up @@ -50,13 +51,15 @@ import (
type EVMKeeper interface {
// Setup initializes the EVM keeper.
Setup(evmkeeper.Blockchain) error
PrepareCheckState(context.Context) error
}

// CosmosApp is an interface that defines the methods needed for the Cosmos setup.
type CosmosApp interface {
SetPrepareProposal(sdk.PrepareProposalHandler)
SetMempool(mempool.Mempool)
SetAnteHandler(sdk.AnteHandler)
miner.App
}

// Polaris is a struct that wraps the Polaris struct from the polar package.
Expand Down Expand Up @@ -92,17 +95,17 @@ func New(
panic(err)
}
itsdevbear marked this conversation as resolved.
Show resolved Hide resolved

// Wrap the geth miner and txpool with the cosmos miner and txpool.
p.WrappedTxPool = txpool.New(p.Blockchain(), p.TxPool())
p.WrappedMiner = miner.New(p.Miner())

return p
}

// Build is a function that sets up the Polaris struct.
// It takes a BaseApp and an EVMKeeper as arguments.
// It returns an error if the setup fails.
func (p *Polaris) Build(app CosmosApp, ek EVMKeeper) error {
// Wrap the geth miner and txpool with the cosmos miner and txpool.
p.WrappedTxPool = txpool.New(p.Blockchain(), p.TxPool())
p.WrappedMiner = miner.New(p.Miner(), app, ek)

app.SetMempool(p.WrappedTxPool)
app.SetPrepareProposal(p.WrappedMiner.PrepareProposal)

Expand Down
4 changes: 3 additions & 1 deletion cosmos/x/evm/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ func (k *Keeper) Precommit(ctx context.Context) error {
block := k.chain.GetBlockByNumber(blockNum)
if block == nil {
panic(
fmt.Sprintf("EVM BLOCK FAILURE AT BLOCK %d", blockNum),
fmt.Sprintf(
"EVM BLOCK %d FAILED TO PROCESS", blockNum,
),
)
} else if block.NumberU64() != blockNum {
panic(
Expand Down
5 changes: 2 additions & 3 deletions cosmos/x/evm/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ func (k *Keeper) InitGenesis(ctx sdk.Context, genState *core.Genesis) error {
}

// Insert to chain.
k.chain.
PreparePlugins(ctx.WithEventManager(sdk.NewEventManager()))
return k.chain.InsertBlockWithoutSetHead(genState.ToBlock())
k.chain.PreparePlugins(ctx.WithEventManager(sdk.NewEventManager()))
return k.chain.WriteGenesisBlock(genState.ToBlock())
}

// ExportGenesis returns the exported genesis state.
Expand Down
7 changes: 4 additions & 3 deletions cosmos/x/evm/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,17 @@ import (
"pkg.berachain.dev/polaris/cosmos/config"
"pkg.berachain.dev/polaris/cosmos/x/evm/plugins/state"
"pkg.berachain.dev/polaris/cosmos/x/evm/types"
"pkg.berachain.dev/polaris/eth/core"
ethprecompile "pkg.berachain.dev/polaris/eth/core/precompile"
coretypes "pkg.berachain.dev/polaris/eth/core/types"
"pkg.berachain.dev/polaris/eth/params"
)

type Blockchain interface {
PreparePlugins(context.Context)
Config() *params.ChainConfig
core.ChainWriter
core.ChainReader
WriteGenesisBlock(*coretypes.Block) error
InsertBlockAndSetHead(*coretypes.Block) error
GetBlockByNumber(uint64) *coretypes.Block
}

type Keeper struct {
Expand Down
2 changes: 1 addition & 1 deletion cosmos/x/evm/keeper/processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ func (k *Keeper) ProcessPayloadEnvelope(

// Prepare should be moved to the blockchain? THIS IS VERY HOOD YES NEEDS TO BE MOVED.
k.chain.PreparePlugins(ctx)
itsdevbear marked this conversation as resolved.
Show resolved Hide resolved
if err = k.chain.InsertBlockWithoutSetHead(block); err != nil {
if err = k.chain.InsertBlockAndSetHead(block); err != nil {
return nil, err
}

Expand Down
4 changes: 2 additions & 2 deletions e2e/precompile/contracts/distribution/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ var _ = Describe("Distribution Precompile", func() {
Expect(err).ToNot(HaveOccurred())
ExpectSuccessReceipt(tf.EthClient(), tx)

// Wait for 2 blocks to be produced, to make sure there are rewards.
for i := 0; i < 2; i++ {
// Wait for 5 blocks to be produced, to make sure there are rewards.
for i := 0; i < 5; i++ {
Expect(tf.WaitForNextBlock()).To(Succeed())
}
Comment on lines +124 to 127
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The change from waiting for 2 blocks to 5 blocks is reasonable if it ensures that there are enough blocks produced to have rewards. However, it might increase the test execution time. If the test suite has many tests that wait for blocks, this could significantly slow down the overall test execution. Consider if there's a more efficient way to ensure that enough blocks are produced, such as by mocking or simulating block production.


Expand Down
2 changes: 1 addition & 1 deletion e2e/testapp/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ func NewPolarisApp(
)

// Setup Polaris Runtime.
if err := app.Polaris.Build(app.BaseApp, app.EVMKeeper); err != nil {
if err := app.Polaris.Build(app, app.EVMKeeper); err != nil {
panic(err)
}

Expand Down
21 changes: 9 additions & 12 deletions eth/core/chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type blockchain struct {

engine consensus.Engine
processor core.Processor
validator core.Validator

// statedb is the state database that is used to mange state during transactions.
statedb state.StateDB
Expand All @@ -79,10 +80,6 @@ type blockchain struct {
currentBlock atomic.Pointer[types.Block]
// finalizedBlock is the finalized/latest block.
finalizedBlock atomic.Pointer[types.Block]
// currentReceipts is the current/pending receipts.
currentReceipts atomic.Value
// currentLogs is the current/pending logs.
currentLogs atomic.Value

// receiptsCache is a cache of the receipts for the last `defaultCacheSizeBytes` bytes of
// blocks. blockHash -> receipts
Expand All @@ -98,14 +95,13 @@ type blockchain struct {
txLookupCache *lru.Cache[common.Hash, *types.TxLookupEntry]

// subscription event feeds
scope event.SubscriptionScope
chainFeed event.Feed
chainHeadFeed event.Feed
logsFeed event.Feed
pendingLogsFeed event.Feed
rmLogsFeed event.Feed // currently never used
chainSideFeed event.Feed // currently never used
logger log.Logger
scope event.SubscriptionScope
chainFeed event.Feed
chainHeadFeed event.Feed
logsFeed event.Feed
rmLogsFeed event.Feed // currently never used
chainSideFeed event.Feed // currently never used
logger log.Logger
}

// =========================================================================
Expand Down Expand Up @@ -134,6 +130,7 @@ func NewChain(
}
bc.statedb = state.NewStateDB(bc.sp, bc.pp)
bc.processor = core.NewStateProcessor(bc.config, bc, bc.engine)
bc.validator = core.NewBlockValidator(bc.config, bc, bc.engine)
// TODO: hmm...
bc.currentBlock.Store(
types.NewBlock(&types.Header{Time: 0, Number: big.NewInt(0),
itsdevbear marked this conversation as resolved.
Show resolved Hide resolved
Expand Down
1 change: 0 additions & 1 deletion eth/core/chain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ func (bc *blockchain) CurrentFinalBlock() *types.Header {
// CurrentSafeBlock retrieves the current safe block of the canonical
// chain. The block is retrieved from the blockchain's internal cache.
func (bc *blockchain) CurrentSafeBlock() *types.Header {
// TODO: determine the difference between safe and final in polaris.
return bc.CurrentFinalBlock()
}

Expand Down
21 changes: 21 additions & 0 deletions eth/core/chain_resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,27 @@ func (bc *blockchain) StateAtBlockNumber(number uint64) (state.StateDB, error) {
return state.NewStateDB(sp, bc.pp), nil
}

// HasBlockAndState checks if the blockchain has a block and its state at
// a given hash and number.
func (bc *blockchain) HasBlockAndState(hash common.Hash, number uint64) bool {
// Check for State.
if sdb, err := bc.StateAt(hash); sdb == nil || err == nil {
sdb, err = bc.StateAtBlockNumber(number)
if sdb == nil || err != nil {
return false
}
}

// Check for Block.
if block := bc.GetBlockByNumber(number); block == nil {
block = bc.GetBlockByHash(hash)
if block == nil {
return false
}
}
return true
}
itsdevbear marked this conversation as resolved.
Show resolved Hide resolved

// GetVMConfig returns the vm.Config for the current chain.
func (bc *blockchain) GetVMConfig() *vm.Config {
return bc.vmConfig
Expand Down
Loading
Loading