Skip to content

Commit

Permalink
Transactional store (#57)
Browse files Browse the repository at this point in the history
* Adds TransactionalStore- a structure that batches updates to the confidential engine
* Rewrites ConfidentialStoreEngine to account for batched updates - InitializeBid now does not store anything on the backend, and Store function is now absent. Adds Finalize function to the engine, which writes a batch of updates to the store backend
* Unifies MEVM execution in eth api behind runMEVM function
* Removes transactions from ConfidentialStore interface, passing transaction around is now managed by TransactionalStore
* Splits EthAPIBackend.GetEVM into two - suave-only GetMEVM and non-suave only GetEVM
* EthAPIBackend.GetMEVM now also returns a finalization function which causes the batched writes to confidential store to be applied
* Minor QoL improvements in testing
  • Loading branch information
Ruteri authored Oct 4, 2023
1 parent 55f1905 commit 892e2e1
Show file tree
Hide file tree
Showing 19 changed files with 675 additions and 347 deletions.
10 changes: 5 additions & 5 deletions core/vm/contracts_suave.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func (c *confStoreStore) runImpl(suaveContext *SuaveContext, bidId suave.BidId,
confStorePrecompileStoreMeter.Mark(int64(len(data)))
}

_, err := suaveContext.Backend.ConfidentialStoreEngine.Store(bidId, suaveContext.ConfidentialComputeRequestTx, caller, key, data)
_, err := suaveContext.Backend.ConfidentialStore.Store(bidId, caller, key, data)
if err != nil {
return err
}
Expand Down Expand Up @@ -195,7 +195,7 @@ func (c *confStoreRetrieve) runImpl(suaveContext *SuaveContext, bidId suave.BidI
}
}

data, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(bidId, caller, key)
data, err := suaveContext.Backend.ConfidentialStore.Retrieve(bidId, caller, key)
if err != nil {
return []byte(err.Error()), err
}
Expand Down Expand Up @@ -250,13 +250,13 @@ func (c *newBid) runImpl(suaveContext *SuaveContext, version string, decryptionC
panic("newBid: source transaction not present")
}

bid, err := suaveContext.Backend.ConfidentialStoreEngine.InitializeBid(types.Bid{
bid, err := suaveContext.Backend.ConfidentialStore.InitializeBid(types.Bid{
Salt: suave.RandomBidId(),
DecryptionCondition: decryptionCondition,
AllowedPeekers: allowedPeekers,
AllowedStores: allowedStores,
Version: version, // TODO : make generic
}, suaveContext.ConfidentialComputeRequestTx)
})
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -300,7 +300,7 @@ func (c *fetchBids) RunConfidential(suaveContext *SuaveContext, input []byte) ([
}

func (c *fetchBids) runImpl(suaveContext *SuaveContext, targetBlock uint64, namespace string) ([]types.Bid, error) {
bids1 := suaveContext.Backend.ConfidentialStoreEngine.FetchBidsByProtocolAndBlock(targetBlock, namespace)
bids1 := suaveContext.Backend.ConfidentialStore.FetchBidsByProtocolAndBlock(targetBlock, namespace)

bids := make([]types.Bid, 0, len(bids1))
for _, bid := range bids1 {
Expand Down
14 changes: 7 additions & 7 deletions core/vm/contracts_suave_eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (c *buildEthBlock) RunConfidential(suaveContext *SuaveContext, input []byte
func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.BuildBlockArgs, bidId types.BidId, namespace string) ([]byte, []byte, error) {
bidIds := [][16]byte{}
// first check for merged bid, else assume regular bid
if mergedBidsBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(bidId, buildEthBlockAddress, "default:v0:mergedBids"); err == nil {
if mergedBidsBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(bidId, buildEthBlockAddress, "default:v0:mergedBids"); err == nil {
unpacked, err := bidIdsAbi.Inputs.Unpack(mergedBidsBytes)

if err != nil {
Expand All @@ -217,7 +217,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil
for i, bidId := range bidIds {
var err error

bid, err := suaveContext.Backend.ConfidentialStoreEngine.FetchBidById(bidId)
bid, err := suaveContext.Backend.ConfidentialStore.FetchBidById(bidId)
if err != nil {
return nil, nil, fmt.Errorf("could not fetch bid id %v: %w", bidId, err)
}
Expand All @@ -229,7 +229,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil
switch bid.Version {
case "mevshare:v0:matchBids":
// fetch the matched ids and merge the bundle
matchedBundleIdsBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(bid.Id, buildEthBlockAddress, "mevshare:v0:mergedBids")
matchedBundleIdsBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(bid.Id, buildEthBlockAddress, "mevshare:v0:mergedBids")
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve bid ids data for bid %v, from cdas: %w", bid, err)
}
Expand All @@ -241,7 +241,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil

matchBidIds := unpackedBidIds[0].([][16]byte)

userBundleBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(matchBidIds[0], buildEthBlockAddress, "mevshare:v0:ethBundles")
userBundleBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(matchBidIds[0], buildEthBlockAddress, "mevshare:v0:ethBundles")
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve bundle data for bidId %v: %w", matchBidIds[0], err)
}
Expand All @@ -251,7 +251,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil
return nil, nil, fmt.Errorf("could not unmarshal user bundle data for bidId %v: %w", matchBidIds[0], err)
}

matchBundleBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(matchBidIds[1], buildEthBlockAddress, "mevshare:v0:ethBundles")
matchBundleBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(matchBidIds[1], buildEthBlockAddress, "mevshare:v0:ethBundles")
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve match bundle data for bidId %v: %w", matchBidIds[1], err)
}
Expand All @@ -266,7 +266,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil
mergedBundles = append(mergedBundles, userBundle)

case "mevshare:v0:unmatchedBundles":
bundleBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(bid.Id, buildEthBlockAddress, "mevshare:v0:ethBundles")
bundleBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(bid.Id, buildEthBlockAddress, "mevshare:v0:ethBundles")
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve bundle data for bidId %v, from cdas: %w", bid.Id, err)
}
Expand All @@ -277,7 +277,7 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil
}
mergedBundles = append(mergedBundles, bundle)
case "default:v0:ethBundles":
bundleBytes, err := suaveContext.Backend.ConfidentialStoreEngine.Retrieve(bid.Id, buildEthBlockAddress, "default:v0:ethBundles")
bundleBytes, err := suaveContext.Backend.ConfidentialStore.Retrieve(bid.Id, buildEthBlockAddress, "default:v0:ethBundles")
if err != nil {
return nil, nil, fmt.Errorf("could not retrieve bundle data for bidId %v, from cdas: %w", bid.Id, err)
}
Expand Down
34 changes: 18 additions & 16 deletions core/vm/contracts_suave_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,18 +77,19 @@ func TestSuavePrecompileStub(t *testing.T) {
// This test ensures that the Suave precompile stubs work as expected
// for encoding/decoding.
mockSuaveBackend := &mockSuaveBackend{}
stubEngine, err := suave.NewConfidentialStoreEngine(mockSuaveBackend, mockSuaveBackend, suave.MockSigner{}, suave.MockChainSigner{})
require.NoError(t, err)
stubEngine := suave.NewConfidentialStoreEngine(mockSuaveBackend, mockSuaveBackend, suave.MockSigner{}, suave.MockChainSigner{})

reqTx := types.NewTx(&types.ConfidentialComputeRequest{
ExecutionNode: common.Address{},
Wrapped: *types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil),
})

suaveContext := SuaveContext{
Backend: &SuaveExecutionBackend{
ConfidentialStoreEngine: stubEngine,
ConfidentialEthBackend: mockSuaveBackend,
ConfidentialStore: stubEngine.NewTransactionalStore(reqTx),
ConfidentialEthBackend: mockSuaveBackend,
},
ConfidentialComputeRequestTx: types.NewTx(&types.ConfidentialComputeRequest{
ExecutionNode: common.Address{},
Wrapped: *types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil),
}),
ConfidentialComputeRequestTx: reqTx,
}

statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewMemoryDatabase()), nil)
Expand Down Expand Up @@ -141,22 +142,23 @@ func TestSuavePrecompileStub(t *testing.T) {

func newTestBackend(t *testing.T) *suaveRuntime {
confStore := backends.NewLocalConfidentialStore()
confEngine, err := suave.NewConfidentialStoreEngine(confStore, &suave.MockTransport{}, suave.MockSigner{}, suave.MockChainSigner{})
require.NoError(t, err)
confEngine := suave.NewConfidentialStoreEngine(confStore, &suave.MockTransport{}, suave.MockSigner{}, suave.MockChainSigner{})

require.NoError(t, confEngine.Start())
t.Cleanup(func() { confEngine.Stop() })

reqTx := types.NewTx(&types.ConfidentialComputeRequest{
ExecutionNode: common.Address{},
Wrapped: *types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil),
})

b := &suaveRuntime{
suaveContext: &SuaveContext{
Backend: &SuaveExecutionBackend{
ConfidentialStoreEngine: confEngine,
ConfidentialEthBackend: &mockSuaveBackend{},
ConfidentialStore: confEngine.NewTransactionalStore(reqTx),
ConfidentialEthBackend: &mockSuaveBackend{},
},
ConfidentialComputeRequestTx: types.NewTx(&types.ConfidentialComputeRequest{
ExecutionNode: common.Address{},
Wrapped: *types.NewTransaction(0, common.Address{}, big.NewInt(0), 0, big.NewInt(0), nil),
}),
ConfidentialComputeRequestTx: reqTx,
},
}
return b
Expand Down
8 changes: 4 additions & 4 deletions core/vm/suave.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
// ConfidentialStore represents the API for the confidential store
// required by Suave runtime.
type ConfidentialStore interface {
InitializeBid(bid types.Bid, creationTx *types.Transaction) (types.Bid, error)
Store(bidId suave.BidId, sourceTx *types.Transaction, caller common.Address, key string, value []byte) (suave.Bid, error)
InitializeBid(bid types.Bid) (types.Bid, error)
Store(bidId suave.BidId, caller common.Address, key string, value []byte) (suave.Bid, error)
Retrieve(bid types.BidId, caller common.Address, key string) ([]byte, error)
FetchBidById(suave.BidId) (suave.Bid, error)
FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid
Expand All @@ -30,8 +30,8 @@ type SuaveContext struct {
}

type SuaveExecutionBackend struct {
ConfidentialStoreEngine ConfidentialStore
ConfidentialEthBackend suave.ConfidentialEthBackend
ConfidentialStore ConfidentialStore
ConfidentialEthBackend suave.ConfidentialEthBackend
}

func NewRuntimeSuaveContext(evm *EVM, caller common.Address) *SuaveContext {
Expand Down
38 changes: 26 additions & 12 deletions eth/api_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,13 @@ type EthAPIBackend struct {
allowUnprotectedTxs bool
eth *Ethereum
gpo *gasprice.Oracle
suaveBackend *vm.SuaveExecutionBackend
suaveEngine *suave.ConfidentialStoreEngine
suaveEthBackend suave.ConfidentialEthBackend
}

func (b *EthAPIBackend) SuaveBackend() *vm.SuaveExecutionBackend {
// For testing purposes
return b.suaveBackend
// For testing purposes
func (b *EthAPIBackend) SuaveEngine() *suave.ConfidentialStoreEngine {
return b.suaveEngine
}

// ChainConfig returns the active chain configuration.
Expand Down Expand Up @@ -253,7 +254,7 @@ func (b *EthAPIBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
return nil
}

func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext, suaveCtx *vm.SuaveContext) (*vm.EVM, func() error) {
func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext) (*vm.EVM, func() error) {
if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig()
}
Expand All @@ -265,15 +266,28 @@ func (b *EthAPIBackend) GetEVM(ctx context.Context, msg *core.Message, state *st
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
}

if vmConfig.IsConfidential {
suaveCtxCopy := *suaveCtx
if suaveCtx.Backend == nil {
suaveCtxCopy.Backend = b.suaveBackend
}
return vm.NewConfidentialEVM(suaveCtxCopy, context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error
}

func (b *EthAPIBackend) GetMEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockCtx *vm.BlockContext, suaveCtx *vm.SuaveContext) (*vm.EVM, func() error, func() error) {
if vmConfig == nil {
vmConfig = b.eth.blockchain.GetVMConfig()
}
txContext := core.NewEVMTxContext(msg)
var context vm.BlockContext
if blockCtx != nil {
context = *blockCtx
} else {
return vm.NewEVM(context, txContext, state, b.eth.blockchain.Config(), *vmConfig), state.Error
context = core.NewEVMBlockContext(header, b.eth.BlockChain(), nil)
}

suaveCtxCopy := *suaveCtx
storeTransaction := b.suaveEngine.NewTransactionalStore(suaveCtx.ConfidentialComputeRequestTx)
suaveCtxCopy.Backend = &vm.SuaveExecutionBackend{
ConfidentialStore: storeTransaction,
ConfidentialEthBackend: b.suaveEthBackend,
}
return vm.NewConfidentialEVM(suaveCtxCopy, context, txContext, state, b.eth.blockchain.Config(), *vmConfig), storeTransaction.Finalize, state.Error
}

func (b *EthAPIBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
Expand Down
25 changes: 9 additions & 16 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,6 @@ type Ethereum struct {
lock sync.RWMutex // Protects the variadic fields (e.g. gas price and etherbase)

shutdownTracker *shutdowncheck.ShutdownTracker // Tracks if and when the node has shutdown ungracefully

// Suave fields
ConfidentialStore *suave.ConfidentialStoreEngine
}

// New creates a new Ethereum object (including the
Expand Down Expand Up @@ -233,7 +230,12 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
eth.miner = miner.New(eth, &config.Miner, eth.blockchain.Config(), eth.EventMux(), eth.engine, eth.isLocalBlock)
eth.miner.SetExtra(makeExtraData(config.Miner.ExtraData))

confidentialStoreBackend := suave_backends.NewRedisStoreBackend(config.Suave.RedisStoreUri)
var confidentialStoreBackend suave.ConfidentialStoreBackend
if config.Suave.RedisStoreUri != "" {
confidentialStoreBackend = suave_backends.NewRedisStoreBackend(config.Suave.RedisStoreUri)
} else {
confidentialStoreBackend = suave_backends.NewLocalConfidentialStore()
}

var confidentialStoreTransport suave.StoreTransportTopic
if config.Suave.RedisStorePubsubUri != "" {
Expand All @@ -251,19 +253,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {

suaveDaSigner := &suave_backends.AccountManagerDASigner{Manager: eth.AccountManager()}

confidentialStoreEngine, err := suave.NewConfidentialStoreEngine(confidentialStoreBackend, confidentialStoreTransport, suaveDaSigner, types.LatestSigner(chainConfig))
if err != nil {
return nil, err
}

eth.ConfidentialStore = confidentialStoreEngine
stack.RegisterLifecycle(confidentialStoreEngine)
confidentialStoreEngine := suave.NewConfidentialStoreEngine(confidentialStoreBackend, confidentialStoreTransport, suaveDaSigner, types.LatestSigner(chainConfig))

suaveBackend := &vm.SuaveExecutionBackend{
ConfidentialStoreEngine: confidentialStoreEngine,
ConfidentialEthBackend: suaveEthBackend,
}
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil, suaveBackend}
eth.APIBackend = &EthAPIBackend{stack.Config().ExtRPCEnabled(), stack.Config().AllowUnprotectedTxs, eth, nil, confidentialStoreEngine, suaveEthBackend}
if eth.APIBackend.allowUnprotectedTxs {
log.Info("Unprotected transactions allowed")
}
Expand Down Expand Up @@ -291,6 +283,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
stack.RegisterAPIs(eth.APIs())
stack.RegisterProtocols(eth.Protocols())
stack.RegisterLifecycle(eth)
stack.RegisterLifecycle(confidentialStoreEngine)

// Successful startup; push a marker and check previous unclean shutdowns.
eth.shutdownTracker.MarkStartup()
Expand Down
Loading

0 comments on commit 892e2e1

Please sign in to comment.