Skip to content

feat: implement ciphertext cache preload #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,6 @@
path = tests/evm-benchmarks
url = https://github.com/ipsilon/evm-benchmarks
shallow = true
[submodule "fhevm-go-coproc"]
path = fhevm-go-coproc
url = git@github.com:zama-ai/fhevm-go-coproc.git
[submodule "libs/fhevm-backend"]
path = libs/fhevm-backend
url = https://github.com/zama-ai/fhevm-backend.git
2 changes: 0 additions & 2 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,8 +359,6 @@ func geth(ctx *cli.Context) error {
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
func startNode(ctx *cli.Context, stack *node.Node, isConsole bool) {
debug.Memsize.Add("node", stack)

// Start up the node itself
utils.StartNode(ctx, stack, isConsole)

Expand Down
22 changes: 17 additions & 5 deletions consensus/beacon/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
"github.com/zama-ai/fhevm-go-native/fhevm"
)

// Proof-of-stake protocol constants.
Expand Down Expand Up @@ -349,9 +351,9 @@ func (beacon *Beacon) Prepare(chain consensus.ChainHeaderReader, header *types.H
}

// Finalize implements consensus.Engine and processes withdrawals on top.
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, session fhevm.ExecutorSession) {
if !beacon.IsPoSHeader(header) {
beacon.ethone.Finalize(chain, header, state, body)
beacon.ethone.Finalize(chain, header, state, body, session)
return
}
// Withdrawals processing.
Expand All @@ -362,13 +364,23 @@ func (beacon *Beacon) Finalize(chain consensus.ChainHeaderReader, header *types.
state.AddBalance(w.Address, amount, tracing.BalanceIncreaseWithdrawal)
}
// No block reward which is issued by consensus layer instead.

if session != nil {
blockNumber := header.Number.Int64()
// transactions succeeded, update queues
// so it makes it into intermediate root
err := session.Commit(blockNumber, state)
if err != nil {
log.Error("error during fhevm session commit", "block", blockNumber, "err", err)
}
}
}

// FinalizeAndAssemble implements consensus.Engine, setting the final state and
// assembling the block.
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, session fhevm.ExecutorSession) (*types.Block, error) {
if !beacon.IsPoSHeader(header) {
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts)
return beacon.ethone.FinalizeAndAssemble(chain, header, state, body, receipts, session)
}
shanghai := chain.Config().IsShanghai(header.Number, header.Time)
if shanghai {
Expand All @@ -382,7 +394,7 @@ func (beacon *Beacon) FinalizeAndAssemble(chain consensus.ChainHeaderReader, hea
}
}
// Finalize and assemble the block.
beacon.Finalize(chain, header, state, body)
beacon.Finalize(chain, header, state, body, session)

// Assign the final state root to header.
header.Root = state.IntermediateRoot(true)
Expand Down
7 changes: 4 additions & 3 deletions consensus/clique/clique.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/rpc"
"github.com/ethereum/go-ethereum/trie"
"github.com/zama-ai/fhevm-go-native/fhevm"
"golang.org/x/crypto/sha3"
)

Expand Down Expand Up @@ -580,18 +581,18 @@ func (c *Clique) Prepare(chain consensus.ChainHeaderReader, header *types.Header

// Finalize implements consensus.Engine. There is no post-transaction
// consensus rules in clique, do nothing here.
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
func (c *Clique) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, session fhevm.ExecutorSession) {
// No block rewards in PoA, so the state remains as is
}

// FinalizeAndAssemble implements consensus.Engine, ensuring no uncles are set,
// nor block rewards given, and returns the final block.
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (c *Clique) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, session fhevm.ExecutorSession) (*types.Block, error) {
if len(body.Withdrawals) > 0 {
return nil, errors.New("clique does not support withdrawals")
}
// Finalize block
c.Finalize(chain, header, state, body)
c.Finalize(chain, header, state, body, session)

// Assign the final state root to header.
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
Expand Down
5 changes: 3 additions & 2 deletions consensus/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rpc"
"github.com/zama-ai/fhevm-go-native/fhevm"
)

// ChainHeaderReader defines a small collection of methods needed to access the local
Expand Down Expand Up @@ -88,14 +89,14 @@ type Engine interface {
//
// Note: The state database might be updated to reflect any consensus rules
// that happen at finalization (e.g. block rewards).
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body)
Finalize(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, session fhevm.ExecutorSession)

// FinalizeAndAssemble runs any post-transaction state modifications (e.g. block
// rewards or process withdrawals) and assembles the final block.
//
// Note: The block header and state database might be updated to reflect any
// consensus rules that happen at finalization (e.g. block rewards).
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error)
FinalizeAndAssemble(chain ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, session fhevm.ExecutorSession) (*types.Block, error)

// Seal generates a new sealing request for the given input block and pushes
// the result into the given channel.
Expand Down
7 changes: 4 additions & 3 deletions consensus/ethash/consensus.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
"github.com/zama-ai/fhevm-go-native/fhevm"
"golang.org/x/crypto/sha3"
)

Expand Down Expand Up @@ -502,19 +503,19 @@ func (ethash *Ethash) Prepare(chain consensus.ChainHeaderReader, header *types.H
}

// Finalize implements consensus.Engine, accumulating the block and uncle rewards.
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body) {
func (ethash *Ethash) Finalize(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, session fhevm.ExecutorSession) {
// Accumulate any block and uncle rewards
accumulateRewards(chain.Config(), state, header, body.Uncles)
}

// FinalizeAndAssemble implements consensus.Engine, accumulating the block and
// uncle rewards, setting the final state and assembling the block.
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) (*types.Block, error) {
func (ethash *Ethash) FinalizeAndAssemble(chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, session fhevm.ExecutorSession) (*types.Block, error) {
if len(body.Withdrawals) > 0 {
return nil, errors.New("ethash does not support withdrawals")
}
// Finalize block
ethash.Finalize(chain, header, state, body)
ethash.Finalize(chain, header, state, body, session)

// Assign the final state root to header.
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
Expand Down
10 changes: 10 additions & 0 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -459,6 +459,16 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
}

state, err := bc.State()
if err != nil {
return nil, err
}
// Load ciphertexts to be computed into the cache
err = vm.FhevmExecutor.PreloadCiphertexts(bc.CurrentBlock().Number.Int64(), state)
if err != nil {
return nil, err
}

// Start tx indexer if it's enabled.
if txLookupLimit != nil {
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)
Expand Down
14 changes: 9 additions & 5 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/triedb"
"github.com/gballet/go-verkle"
"github.com/holiman/uint256"
"github.com/zama-ai/fhevm-go-native/fhevm"
)

// BlockGen creates blocks for testing.
Expand All @@ -51,7 +52,8 @@ type BlockGen struct {
uncles []*types.Header
withdrawals []*types.Withdrawal

engine consensus.Engine
fhevmSession fhevm.ExecutorSession
engine consensus.Engine
}

// SetCoinbase sets the coinbase of the generated block.
Expand Down Expand Up @@ -137,7 +139,7 @@ func (b *BlockGen) addTx(bc *BlockChain, vmConfig vm.Config, tx *types.Transacti
// instruction will panic during execution if it attempts to access a block number outside
// of the range created by GenerateChain.
func (b *BlockGen) AddTx(tx *types.Transaction) {
b.addTx(nil, vm.Config{}, tx)
b.addTx(nil, vm.Config{FhevmSession: b.fhevmSession}, tx)
}

// AddTxWithChain adds a transaction to the generated block. If no coinbase has
Expand All @@ -148,7 +150,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
// the content of transactions that can be added. If contract code relies on the BLOCKHASH
// instruction, the block in chain will be returned.
func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
b.addTx(bc, vm.Config{}, tx)
b.addTx(bc, vm.Config{FhevmSession: b.fhevmSession}, tx)
}

// AddTxWithVMConfig adds a transaction to the generated block. If no coinbase has
Expand Down Expand Up @@ -316,6 +318,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
b.header = cm.makeHeader(parent, statedb, b.engine)
b.fhevmSession = vm.FhevmExecutor.CreateSession(b.Number().Int64())

// Set the difficulty for clique block. The chain maker doesn't have access
// to a chain, so the difficulty will be left unset (nil). Set it here to the
Expand Down Expand Up @@ -347,7 +350,7 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
}

body := types.Body{Transactions: b.txs, Uncles: b.uncles, Withdrawals: b.withdrawals}
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts)
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, &body, b.receipts, b.fhevmSession)
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -430,6 +433,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
genblock := func(i int, parent *types.Block, triedb *triedb.Database, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{i: i, cm: cm, parent: parent, statedb: statedb, engine: engine}
b.header = cm.makeHeader(parent, statedb, b.engine)
b.fhevmSession = vm.FhevmExecutor.CreateSession(b.header.Number.Int64())

// TODO uncomment when proof generation is merged
// Save pre state for proof generation
Expand All @@ -453,7 +457,7 @@ func GenerateVerkleChain(config *params.ChainConfig, parent *types.Block, engine
Uncles: b.uncles,
Withdrawals: b.withdrawals,
}
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, body, b.receipts)
block, err := b.engine.FinalizeAndAssemble(cm, b.header, statedb, body, b.receipts, b.fhevmSession)
if err != nil {
panic(err)
}
Expand Down
17 changes: 4 additions & 13 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
)

Expand Down Expand Up @@ -69,6 +68,8 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
gp = new(GasPool).AddGas(block.GasLimit())
)

cfg.FhevmSession = vm.FhevmExecutor.CreateSession(blockNumber.Int64())

// Mutate the block and state according to any hard-fork specs
if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(statedb)
Expand All @@ -89,31 +90,21 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
}
statedb.SetTxContext(tx.Hash(), i)

if vm.FhevmCoprocessor != nil {
vmenv.CoprocessorSession = vm.FhevmCoprocessor.CreateSession()
}
receipt, err := ApplyTransactionWithEVM(msg, p.config, gp, statedb, blockNumber, blockHash, tx, usedGas, vmenv)
if err != nil {
return nil, nil, 0, fmt.Errorf("could not apply tx %d [%v]: %w", i, tx.Hash().Hex(), err)
}
receipts = append(receipts, receipt)
allLogs = append(allLogs, receipt.Logs...)

if vm.FhevmCoprocessor != nil && receipt.Status == types.ReceiptStatusSuccessful {
err = vmenv.CoprocessorSession.Commit()
if err != nil {
// only log, don't return not to halt blockchain
log.Error("coprocessor transaction commit failed", "err", err)
}
}
}

// Fail if Shanghai not enabled and len(withdrawals) is non-zero.
withdrawals := block.Withdrawals()
if len(withdrawals) > 0 && !p.config.IsShanghai(block.Number(), block.Time()) {
return nil, nil, 0, errors.New("withdrawals before shanghai")
}
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
p.engine.Finalize(p.bc, header, statedb, block.Body())
p.engine.Finalize(p.bc, header, statedb, block.Body(), cfg.FhevmSession)

return receipts, allLogs, *usedGas, nil
}
Expand Down
24 changes: 12 additions & 12 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/holiman/uint256"
"github.com/zama-ai/fhevm-go-coproc/fhevm"
"github.com/zama-ai/fhevm-go-native/fhevm"
)

type (
Expand Down Expand Up @@ -125,17 +125,17 @@ type EVM struct {
// callGasTemp holds the gas available for the current call. This is needed because the
// available gas is calculated in gasCall* according to the 63/64 rule and later
// applied in opCall*.
callGasTemp uint64
CoprocessorSession fhevm.CoprocessorSession
callGasTemp uint64
ExecutorSession fhevm.ExecutorSession
}

var FhevmCoprocessor fhevm.CoprocessorApi
var FhevmExecutor fhevm.ExecutorApi

// hacky, and this is for demo, but we need a lot of refactorings
// of NewEVM method otherwise
func init() {
var err error
FhevmCoprocessor, err = fhevm.InitCoprocessor()
FhevmExecutor, err = fhevm.InitExecutor()
if err != nil {
panic(err)
}
Expand All @@ -156,13 +156,13 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
}
}
evm := &EVM{
Context: blockCtx,
TxContext: txCtx,
StateDB: statedb,
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
CoprocessorSession: nil,
Context: blockCtx,
TxContext: txCtx,
StateDB: statedb,
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil, blockCtx.Time),
ExecutorSession: config.FhevmSession,
}
evm.interpreter = NewEVMInterpreter(evm)
return evm
Expand Down
Loading