From c4b3746c5d4b13545793c70e0969f80f73f3ab2b Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Sat, 30 Sep 2023 00:05:06 +0200 Subject: [PATCH 1/5] Create engine store api --- core/vm/contracts_suave.go | 8 ++- core/vm/contracts_suave_eth.go | 3 +- core/vm/contracts_suave_test.go | 11 ++- core/vm/suave.go | 4 +- eth/backend.go | 3 +- suave/backends/backend_testing.go | 36 ++++++++++ suave/backends/mempool_on_cdas.go | 82 ---------------------- suave/backends/redis_backends_test.go | 35 +-------- suave/backends/redis_store_backend.go | 52 +++++++++++++- suave/backends/redis_store_backend_test.go | 14 ++++ suave/core/engine.go | 46 +++--------- suave/core/engine_test.go | 14 +++- suave/core/types.go | 21 +++--- suave/e2e/workflow_test.go | 12 ++-- 14 files changed, 162 insertions(+), 179 deletions(-) create mode 100644 suave/backends/backend_testing.go delete mode 100644 suave/backends/mempool_on_cdas.go create mode 100644 suave/backends/redis_store_backend_test.go diff --git a/core/vm/contracts_suave.go b/core/vm/contracts_suave.go index e4e2805cf7..07580e4c60 100644 --- a/core/vm/contracts_suave.go +++ b/core/vm/contracts_suave.go @@ -300,7 +300,13 @@ func (c *fetchBids) RunConfidential(suaveContext *SuaveContext, input []byte) ([ } func (c *fetchBids) runImpl(suaveContext *SuaveContext, targetBlock uint64, namespace string) ([]types.Bid, error) { - bids := suaveContext.Backend.ConfidentialStoreEngine.FetchBidsByProtocolAndBlock(targetBlock, namespace) + bids1 := suaveContext.Backend.ConfidentialStoreEngine.FetchBidsByProtocolAndBlock(targetBlock, namespace) + + bids := make([]types.Bid, 0, len(bids1)) + for _, bid := range bids1 { + bids = append(bids, bid.ToInnerBid()) + } + return bids, nil } diff --git a/core/vm/contracts_suave_eth.go b/core/vm/contracts_suave_eth.go index 937323be4f..a44ee04362 100644 --- a/core/vm/contracts_suave_eth.go +++ b/core/vm/contracts_suave_eth.go @@ -217,10 +217,11 @@ func (c *buildEthBlock) runImpl(suaveContext *SuaveContext, blockArgs types.Buil for i, bidId := range bidIds { var err error - bidsToMerge[i], err = suaveContext.Backend.ConfidentialStoreEngine.FetchBidById(bidId) + bid, err := suaveContext.Backend.ConfidentialStoreEngine.FetchBidById(bidId) if err != nil { return nil, nil, fmt.Errorf("could not fetch bid id %v: %w", bidId, err) } + bidsToMerge[i] = bid.ToInnerBid() } var mergedBundles []types.SBundle diff --git a/core/vm/contracts_suave_test.go b/core/vm/contracts_suave_test.go index b295067e41..7543815782 100644 --- a/core/vm/contracts_suave_test.go +++ b/core/vm/contracts_suave_test.go @@ -45,11 +45,11 @@ func (m *mockSuaveBackend) FetchEngineBidById(suave.BidId) (suave.Bid, error) { return suave.Bid{}, nil } -func (m *mockSuaveBackend) FetchBidById(suave.BidId) (types.Bid, error) { - return types.Bid{}, nil +func (m *mockSuaveBackend) FetchBidById(suave.BidId) (suave.Bid, error) { + return suave.Bid{}, nil } -func (m *mockSuaveBackend) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid { +func (m *mockSuaveBackend) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid { return nil } @@ -77,7 +77,7 @@ 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.MockMempool{}, suave.MockSigner{}, suave.MockChainSigner{}) + stubEngine, err := suave.NewConfidentialStoreEngine(mockSuaveBackend, mockSuaveBackend, suave.MockSigner{}, suave.MockChainSigner{}) require.NoError(t, err) suaveContext := SuaveContext{ @@ -141,8 +141,7 @@ func TestSuavePrecompileStub(t *testing.T) { func newTestBackend(t *testing.T) *suaveRuntime { confStore := backends.NewLocalConfidentialStore() - suaveMempool := backends.NewMempoolOnConfidentialStore(confStore) - confEngine, err := suave.NewConfidentialStoreEngine(confStore, &suave.MockTransport{}, suaveMempool, suave.MockSigner{}, suave.MockChainSigner{}) + confEngine, err := suave.NewConfidentialStoreEngine(confStore, &suave.MockTransport{}, suave.MockSigner{}, suave.MockChainSigner{}) require.NoError(t, err) require.NoError(t, confEngine.Start()) diff --git a/core/vm/suave.go b/core/vm/suave.go index 5285df8f69..e58810122e 100644 --- a/core/vm/suave.go +++ b/core/vm/suave.go @@ -17,8 +17,8 @@ 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) Retrieve(bid types.BidId, caller common.Address, key string) ([]byte, error) - FetchBidById(suave.BidId) (types.Bid, error) - FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid + FetchBidById(suave.BidId) (suave.Bid, error) + FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid } type SuaveContext struct { diff --git a/eth/backend.go b/eth/backend.go index 6836f3b989..03864871a3 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -248,10 +248,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { suaveEthBackend = &suave_backends.EthMock{} } - suaveBidMempool := suave_backends.NewMempoolOnConfidentialStore(confidentialStoreBackend) suaveDaSigner := &suave_backends.AccountManagerDASigner{Manager: eth.AccountManager()} - confidentialStoreEngine, err := suave.NewConfidentialStoreEngine(confidentialStoreBackend, confidentialStoreTransport, suaveBidMempool, suaveDaSigner, types.LatestSigner(chainConfig)) + confidentialStoreEngine, err := suave.NewConfidentialStoreEngine(confidentialStoreBackend, confidentialStoreTransport, suaveDaSigner, types.LatestSigner(chainConfig)) if err != nil { return nil, err } diff --git a/suave/backends/backend_testing.go b/suave/backends/backend_testing.go new file mode 100644 index 0000000000..49232b2dbc --- /dev/null +++ b/suave/backends/backend_testing.go @@ -0,0 +1,36 @@ +package backends + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common" + suave "github.com/ethereum/go-ethereum/suave/core" + "github.com/stretchr/testify/require" +) + +func testBackendStore(t *testing.T, store suave.ConfidentialStoreBackend) { + bid := suave.Bid{ + Id: suave.RandomBidId(), + DecryptionCondition: 10, + AllowedPeekers: []common.Address{common.HexToAddress("0x424344")}, + Version: "default:v0:ethBundles", + } + + err := store.InitializeBid(bid) + require.NoError(t, err) + + bidRes, err := store.FetchBidById(bid.Id) + require.NoError(t, err) + require.Equal(t, bid, bidRes) + + _, err = store.Store(bid, bid.AllowedPeekers[0], "xx", []byte{0x43, 0x14}) + require.NoError(t, err) + + retrievedData, err := store.Retrieve(bid, bid.AllowedPeekers[0], "xx") + require.NoError(t, err) + require.Equal(t, []byte{0x43, 0x14}, retrievedData) + + bids := store.FetchBidsByProtocolAndBlock(10, "default:v0:ethBundles") + require.Len(t, bids, 1) + require.Equal(t, bid, bids[0]) +} diff --git a/suave/backends/mempool_on_cdas.go b/suave/backends/mempool_on_cdas.go deleted file mode 100644 index 95a48b5ac3..0000000000 --- a/suave/backends/mempool_on_cdas.go +++ /dev/null @@ -1,82 +0,0 @@ -package backends - -import ( - "errors" - "fmt" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/log" - suave "github.com/ethereum/go-ethereum/suave/core" -) - -type MempoolOnConfidentialStore struct { - cs suave.ConfidentialStoreBackend -} - -func NewMempoolOnConfidentialStore(cs suave.ConfidentialStoreBackend) *MempoolOnConfidentialStore { - return &MempoolOnConfidentialStore{ - cs: cs, - } -} - -func (m *MempoolOnConfidentialStore) Start() error { - err := m.cs.InitializeBid(mempoolConfidentialStoreBid) - if err != nil && !errors.Is(err, suave.ErrBidAlreadyPresent) { - return fmt.Errorf("mempool: could not initialize: %w", err) - } - - return nil -} - -func (m *MempoolOnConfidentialStore) Stop() error { - return nil -} - -var ( - mempoolConfStoreId = types.BidId{0x39} - mempoolConfStoreAddr = common.HexToAddress("0x39") - mempoolConfidentialStoreBid = suave.Bid{Id: mempoolConfStoreId, AllowedPeekers: []common.Address{mempoolConfStoreAddr}} -) - -func (m *MempoolOnConfidentialStore) SubmitBid(bid types.Bid) error { - defer log.Info("bid submitted", "bid", bid, "store", m.cs.Store) - - var bidsByBlockAndProtocol []types.Bid - bidsByBlockAndProtocolBytes, err := m.cs.Retrieve(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", bid.Version, bid.DecryptionCondition)) - if err == nil { - bidsByBlockAndProtocol = suave.MustDecode[[]types.Bid](bidsByBlockAndProtocolBytes) - } - // store bid by block number and by protocol + block number - bidsByBlockAndProtocol = append(bidsByBlockAndProtocol, bid) - - m.cs.Store(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", bid.Version, bid.DecryptionCondition), suave.MustEncode(bidsByBlockAndProtocol)) - - return nil -} - -func (m *MempoolOnConfidentialStore) FetchBidById(bidId suave.BidId) (types.Bid, error) { - engineBid, err := m.cs.FetchEngineBidById(bidId) - if err != nil { - log.Error("bid missing!", "id", bidId, "err", err) - return types.Bid{}, errors.New("not found") - } - - return types.Bid{ - Id: engineBid.Id, - Salt: engineBid.Salt, - DecryptionCondition: engineBid.DecryptionCondition, - AllowedPeekers: engineBid.AllowedPeekers, - AllowedStores: engineBid.AllowedStores, - Version: engineBid.Version, - }, nil -} - -func (m *MempoolOnConfidentialStore) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid { - bidsByProtocolBytes, err := m.cs.Retrieve(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", namespace, blockNumber)) - if err != nil { - return nil - } - defer log.Info("bids fetched", "bids", string(bidsByProtocolBytes)) - return suave.MustDecode[[]types.Bid](bidsByProtocolBytes) -} diff --git a/suave/backends/redis_backends_test.go b/suave/backends/redis_backends_test.go index e13734dfa3..4bbc53be5b 100644 --- a/suave/backends/redis_backends_test.go +++ b/suave/backends/redis_backends_test.go @@ -60,35 +60,6 @@ func TestRedisTransport(t *testing.T) { } } -func TestRedisStore(t *testing.T) { - mr := miniredis.RunT(t) - - redisStoreBackend := NewRedisStoreBackend(mr.Addr()) - redisStoreBackend.Start() - t.Cleanup(func() { redisStoreBackend.Stop() }) - - bid := suave.Bid{ - Id: suave.BidId{0x42}, - DecryptionCondition: uint64(13), - AllowedPeekers: []common.Address{{0x41, 0x39}}, - Version: string("vv"), - } - - err := redisStoreBackend.InitializeBid(bid) - require.NoError(t, err) - - fetchedBid, err := redisStoreBackend.FetchEngineBidById(bid.Id) - require.NoError(t, err) - require.Equal(t, bid, fetchedBid) - - _, err = redisStoreBackend.Store(bid, bid.AllowedPeekers[0], "xx", []byte{0x43, 0x14}) - require.NoError(t, err) - - retrievedData, err := redisStoreBackend.Retrieve(bid, bid.AllowedPeekers[0], "xx") - require.NoError(t, err) - require.Equal(t, []byte{0x43, 0x14}, retrievedData) -} - func TestEngineOnRedis(t *testing.T) { mrStore1 := miniredis.RunT(t) mrStore2 := miniredis.RunT(t) @@ -97,7 +68,7 @@ func TestEngineOnRedis(t *testing.T) { redisPubSub1 := NewRedisPubSubTransport(mrPubSub.Addr()) redisStoreBackend1 := NewRedisStoreBackend(mrStore1.Addr()) - engine1, err := suave.NewConfidentialStoreEngine(redisStoreBackend1, redisPubSub1, suave.MockMempool{}, suave.MockSigner{}, suave.MockChainSigner{}) + engine1, err := suave.NewConfidentialStoreEngine(redisStoreBackend1, redisPubSub1, suave.MockSigner{}, suave.MockChainSigner{}) require.NoError(t, err) require.NoError(t, engine1.Start()) @@ -106,7 +77,7 @@ func TestEngineOnRedis(t *testing.T) { redisPubSub2 := NewRedisPubSubTransport(mrPubSub.Addr()) redisStoreBackend2 := NewRedisStoreBackend(mrStore2.Addr()) - engine2, err := suave.NewConfidentialStoreEngine(redisStoreBackend2, redisPubSub2, suave.MockMempool{}, suave.MockSigner{}, suave.MockChainSigner{}) + engine2, err := suave.NewConfidentialStoreEngine(redisStoreBackend2, redisPubSub2, suave.MockSigner{}, suave.MockChainSigner{}) require.NoError(t, err) require.NoError(t, engine2.Start()) @@ -174,7 +145,7 @@ func TestEngineOnRedis(t *testing.T) { require.NoError(t, err) require.Equal(t, []byte{0x43, 0x14}, retrievedData) - fetchedBid, err := redisStoreBackend2.FetchEngineBidById(bid.Id) + fetchedBid, err := redisStoreBackend2.FetchBidById(bid.Id) require.NoError(t, err) fetchedBidJson, err := json.Marshal(fetchedBid) diff --git a/suave/backends/redis_store_backend.go b/suave/backends/redis_store_backend.go index 93568486c3..08611829ff 100644 --- a/suave/backends/redis_store_backend.go +++ b/suave/backends/redis_store_backend.go @@ -9,6 +9,8 @@ import ( "github.com/alicebob/miniredis/v2" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/log" suave "github.com/ethereum/go-ethereum/suave/core" "github.com/go-redis/redis/v8" ) @@ -104,10 +106,15 @@ func (r *RedisStoreBackend) InitializeBid(bid suave.Bid) error { return err } + err = r.indexBid(bid) + if err != nil { + return err + } + return nil } -func (r *RedisStoreBackend) FetchEngineBidById(bidId suave.BidId) (suave.Bid, error) { +func (r *RedisStoreBackend) FetchBidById(bidId suave.BidId) (suave.Bid, error) { key := formatRedisBidKey(bidId) data, err := r.client.Get(r.ctx, key).Bytes() @@ -143,3 +150,46 @@ func (r *RedisStoreBackend) Retrieve(bid suave.Bid, caller common.Address, key s return data, nil } + +var ( + mempoolConfStoreId = types.BidId{0x39} + mempoolConfStoreAddr = common.HexToAddress("0x39") + mempoolConfidentialStoreBid = suave.Bid{Id: mempoolConfStoreId, AllowedPeekers: []common.Address{mempoolConfStoreAddr}} +) + +func (r *RedisStoreBackend) indexBid(bid suave.Bid) error { + defer log.Info("bid submitted", "bid", bid, "store", r.Store) + + var bidsByBlockAndProtocol []suave.BidId + bidsByBlockAndProtocolBytes, err := r.Retrieve(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", bid.Version, bid.DecryptionCondition)) + if err == nil { + bidsByBlockAndProtocol = suave.MustDecode[[]suave.BidId](bidsByBlockAndProtocolBytes) + } + // store bid by block number and by protocol + block number + bidsByBlockAndProtocol = append(bidsByBlockAndProtocol, bid.Id) + + r.Store(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", bid.Version, bid.DecryptionCondition), suave.MustEncode(bidsByBlockAndProtocol)) + + return nil +} + +func (r *RedisStoreBackend) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid { + bidsByProtocolBytes, err := r.Retrieve(mempoolConfidentialStoreBid, mempoolConfStoreAddr, fmt.Sprintf("protocol-%s-bn-%d", namespace, blockNumber)) + if err != nil { + return nil + } + + res := []suave.Bid{} + + bidIDs := suave.MustDecode[[]suave.BidId](bidsByProtocolBytes) + for _, id := range bidIDs { + bid, err := r.FetchBidById(id) + if err != nil { + continue + } + res = append(res, bid) + } + + // defer log.Info("bids fetched", "bids", string(bidsByProtocolBytes)) + return res +} diff --git a/suave/backends/redis_store_backend_test.go b/suave/backends/redis_store_backend_test.go new file mode 100644 index 0000000000..07db156de7 --- /dev/null +++ b/suave/backends/redis_store_backend_test.go @@ -0,0 +1,14 @@ +package backends + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestRedis_StoreSuite(t *testing.T) { + store := NewRedisStoreBackend("") + require.NoError(t, store.Start()) + + testBackendStore(t, store) +} diff --git a/suave/core/engine.go b/suave/core/engine.go index 074355541b..d4cbadd3af 100644 --- a/suave/core/engine.go +++ b/suave/core/engine.go @@ -19,7 +19,6 @@ type ConfidentialStoreEngine struct { backend ConfidentialStoreBackend transportTopic StoreTransportTopic - mempool MempoolBackend daSigner DASigner chainSigner ChainSigner @@ -37,10 +36,6 @@ func (e *ConfidentialStoreEngine) Start() error { return err } - if err := e.mempool.Start(); err != nil { - return err - } - if e.cancel != nil { e.cancel() } @@ -59,9 +54,6 @@ func (e *ConfidentialStoreEngine) Stop() error { } e.cancel() - if err := e.mempool.Stop(); err != nil { - log.Warn("Confidential engine: error while stopping mempool", "err", err) - } if err := e.transportTopic.Stop(); err != nil { log.Warn("Confidential engine: error while stopping transport", "err", err) @@ -84,7 +76,7 @@ type ChainSigner interface { Sender(tx *types.Transaction) (common.Address, error) } -func NewConfidentialStoreEngine(backend ConfidentialStoreBackend, transportTopic StoreTransportTopic, mempool MempoolBackend, daSigner DASigner, chainSigner ChainSigner) (*ConfidentialStoreEngine, error) { +func NewConfidentialStoreEngine(backend ConfidentialStoreBackend, transportTopic StoreTransportTopic, daSigner DASigner, chainSigner ChainSigner) (*ConfidentialStoreEngine, error) { localAddresses := make(map[common.Address]struct{}) for _, addr := range daSigner.LocalAddresses() { localAddresses[addr] = struct{}{} @@ -93,7 +85,6 @@ func NewConfidentialStoreEngine(backend ConfidentialStoreBackend, transportTopic engine := &ConfidentialStoreEngine{ backend: backend, transportTopic: transportTopic, - mempool: mempool, daSigner: daSigner, chainSigner: chainSigner, storeUUID: uuid.New(), @@ -179,28 +170,23 @@ func (e *ConfidentialStoreEngine) InitializeBid(bid types.Bid, creationTx *types return types.Bid{}, fmt.Errorf("confidential engine: store backend failed to initialize bid: %w", err) } - // send the bid to the internal mempool - if err := e.mempool.SubmitBid(bid); err != nil { - return types.Bid{}, fmt.Errorf("failed to submit to mempool: %w", err) - } - return bid, nil } -func (e *ConfidentialStoreEngine) SubmitBid(bid types.Bid) error { - return e.mempool.SubmitBid(bid) +func (e *ConfidentialStoreEngine) StoreBid(bid Bid) error { + return e.backend.InitializeBid(bid) } -func (e *ConfidentialStoreEngine) FetchBidById(bidId BidId) (types.Bid, error) { - return e.mempool.FetchBidById(bidId) +func (e *ConfidentialStoreEngine) FetchBidById(bidId BidId) (Bid, error) { + return e.backend.FetchBidById(bidId) } -func (e *ConfidentialStoreEngine) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid { - return e.mempool.FetchBidsByProtocolAndBlock(blockNumber, namespace) +func (e *ConfidentialStoreEngine) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []Bid { + return e.backend.FetchBidsByProtocolAndBlock(blockNumber, namespace) } func (e *ConfidentialStoreEngine) Store(bidId BidId, sourceTx *types.Transaction, caller common.Address, key string, value []byte) (Bid, error) { - bid, err := e.backend.FetchEngineBidById(bidId) + bid, err := e.backend.FetchBidById(bidId) if err != nil { return Bid{}, fmt.Errorf("confidential engine: could not fetch bid %x while storing: %w", bidId, err) } @@ -240,7 +226,7 @@ func (e *ConfidentialStoreEngine) Store(bidId BidId, sourceTx *types.Transaction } func (e *ConfidentialStoreEngine) Retrieve(bidId BidId, caller common.Address, key string) ([]byte, error) { - bid, err := e.backend.FetchEngineBidById(bidId) + bid, err := e.backend.FetchBidById(bidId) if err != nil { return []byte{}, fmt.Errorf("confidential engine: could not fetch bid %x while retrieving: %w", bidId, err) } @@ -338,8 +324,6 @@ func (e *ConfidentialStoreEngine) NewMessage(message DAMessage) error { if !errors.Is(err, ErrBidAlreadyPresent) { return fmt.Errorf("unexpected error while initializing bid from transport: %w", err) } - } else { - e.mempool.SubmitBid(innerBid) } _, err = e.backend.Store(message.Bid, message.Caller, message.Key, message.Value) @@ -405,15 +389,3 @@ func (MockChainSigner) Sender(tx *types.Transaction) (common.Address, error) { return *tx.To(), nil } - -type MockMempool struct{} - -func (MockMempool) Start() error { return nil } -func (MockMempool) Stop() error { return nil } - -func (MockMempool) SubmitBid(types.Bid) error { return nil } - -func (MockMempool) FetchBidById(BidId) (types.Bid, error) { return types.Bid{}, nil } -func (MockMempool) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid { - return nil -} diff --git a/suave/core/engine_test.go b/suave/core/engine_test.go index 581d913d1b..4d4403cdce 100644 --- a/suave/core/engine_test.go +++ b/suave/core/engine_test.go @@ -42,6 +42,18 @@ func (*FakeStoreBackend) Retrieve(bid Bid, caller common.Address, key string) ([ return nil, errors.New("not implemented") } +func (*FakeStoreBackend) FetchBidById(BidId) (Bid, error) { + return Bid{}, nil +} + +func (*FakeStoreBackend) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []Bid { + return nil +} + +func (*FakeStoreBackend) SubmitBid(types.Bid) error { + return nil +} + func TestOwnMessageDropping(t *testing.T) { var wasCalled *bool = new(bool) fakeStore := FakeStoreBackend{OnStore: func(bid Bid, caller common.Address, key string, value []byte) (Bid, error) { @@ -50,7 +62,7 @@ func TestOwnMessageDropping(t *testing.T) { }} fakeDaSigner := FakeDASigner{localAddresses: []common.Address{{0x42}}} - engine, err := NewConfidentialStoreEngine(&fakeStore, MockTransport{}, MockMempool{}, fakeDaSigner, MockChainSigner{}) + engine, err := NewConfidentialStoreEngine(&fakeStore, MockTransport{}, fakeDaSigner, MockChainSigner{}) require.NoError(t, err) dummyCreationTx := types.NewTx(&types.ConfidentialComputeRequest{ diff --git a/suave/core/types.go b/suave/core/types.go index c13aae049f..e6516549ad 100644 --- a/suave/core/types.go +++ b/suave/core/types.go @@ -26,6 +26,17 @@ type Bid struct { Signature []byte } +func (b *Bid) ToInnerBid() types.Bid { + return types.Bid{ + Id: b.Id, + Salt: b.Salt, + DecryptionCondition: b.DecryptionCondition, + AllowedPeekers: b.AllowedPeekers, + AllowedStores: b.AllowedStores, + Version: b.Version, + } +} + type MEVMBid = types.Bid type BuildBlockArgs = types.BuildBlockArgs @@ -37,16 +48,10 @@ var ErrBidAlreadyPresent = errors.New("bid already present") type ConfidentialStoreBackend interface { node.Lifecycle InitializeBid(bid Bid) error - FetchEngineBidById(bidId BidId) (Bid, error) Store(bid Bid, caller common.Address, key string, value []byte) (Bid, error) Retrieve(bid Bid, caller common.Address, key string) ([]byte, error) -} - -type MempoolBackend interface { - node.Lifecycle - SubmitBid(types.Bid) error - FetchBidById(BidId) (types.Bid, error) - FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []types.Bid + FetchBidById(BidId) (Bid, error) + FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []Bid } type ConfidentialEthBackend interface { diff --git a/suave/e2e/workflow_test.go b/suave/e2e/workflow_test.go index 15c4809a8e..4640477c8d 100644 --- a/suave/e2e/workflow_test.go +++ b/suave/e2e/workflow_test.go @@ -137,22 +137,22 @@ func TestMempool(t *testing.T) { { targetBlock := uint64(16103213) - bid1 := types.Bid{ + bid1 := suave.Bid{ Id: suave.RandomBidId(), DecryptionCondition: targetBlock, AllowedPeekers: []common.Address{common.HexToAddress("0x424344")}, Version: "default:v0:ethBundles", } - bid2 := types.Bid{ + bid2 := suave.Bid{ Id: suave.RandomBidId(), DecryptionCondition: targetBlock, AllowedPeekers: []common.Address{common.HexToAddress("0x424344")}, Version: "default:v0:ethBundles", } - require.NoError(t, fr.ConfidentialStore().SubmitBid(bid1)) - require.NoError(t, fr.ConfidentialStore().SubmitBid(bid2)) + require.NoError(t, fr.ConfidentialStore().StoreBid(bid1)) + require.NoError(t, fr.ConfidentialStore().StoreBid(bid2)) inoutAbi := mustParseMethodAbi(`[ { "inputs": [ { "internalType": "uint64", "name": "cond", "type": "uint64" }, { "internalType": "string", "name": "namespace", "type": "string" } ], "name": "fetchBids", "outputs": [ { "components": [ { "internalType": "Suave.BidId", "name": "id", "type": "bytes16" }, { "internalType": "Suave.BidId", "name": "salt", "type": "bytes16" }, { "internalType": "uint64", "name": "decryptionCondition", "type": "uint64" }, { "internalType": "address[]", "name": "allowedPeekers", "type": "address[]" }, { "internalType": "address[]", "name": "allowedStores", "type": "address[]" }, { "internalType": "string", "name": "version", "type": "string" } ], "internalType": "struct Suave.Bid[]", "name": "", "type": "tuple[]" } ], "stateMutability": "view", "type": "function" } ]`, "fetchBids") @@ -174,13 +174,13 @@ func TestMempool(t *testing.T) { var bids []suave.Bid require.NoError(t, mapstructure.Decode(unpacked[0], &bids)) - require.Equal(t, bid1, types.Bid{ + require.Equal(t, bid1, suave.Bid{ Id: bids[0].Id, DecryptionCondition: bids[0].DecryptionCondition, AllowedPeekers: bids[0].AllowedPeekers, Version: bids[0].Version, }) - require.Equal(t, bid2, types.Bid{ + require.Equal(t, bid2, suave.Bid{ Id: bids[1].Id, DecryptionCondition: bids[1].DecryptionCondition, AllowedPeekers: bids[1].AllowedPeekers, From 870747f273f51d1b868c187656d6d10c823d4f68 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Sat, 30 Sep 2023 00:26:14 +0200 Subject: [PATCH 2/5] Fix test --- core/vm/contracts_suave_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/contracts_suave_test.go b/core/vm/contracts_suave_test.go index 7543815782..ec1e27d6d6 100644 --- a/core/vm/contracts_suave_test.go +++ b/core/vm/contracts_suave_test.go @@ -179,10 +179,10 @@ func TestSuave_BidWorkflow(t *testing.T) { namespace string bids []types.Bid }{ - {0, "a", nil}, + {0, "a", []types.Bid{}}, {5, "a", []types.Bid{bid5}}, {10, "a", []types.Bid{bid10, bid10b}}, - {11, "a", nil}, + {11, "a", []types.Bid{}}, } for _, c := range cases { From ae71f643bd1be7b3d29f59d18c0d3758fa7909ba Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Sat, 30 Sep 2023 00:17:26 +0200 Subject: [PATCH 3/5] Add datastore local store --- suave/backends/local_store_backend.go | 107 +++++++++++++++++++++ suave/backends/local_store_backend_test.go | 10 ++ suave/backends/redis_store_backend.go | 6 +- 3 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 suave/backends/local_store_backend.go create mode 100644 suave/backends/local_store_backend_test.go diff --git a/suave/backends/local_store_backend.go b/suave/backends/local_store_backend.go new file mode 100644 index 0000000000..cb9ff390ae --- /dev/null +++ b/suave/backends/local_store_backend.go @@ -0,0 +1,107 @@ +package backends + +import ( + "errors" + "fmt" + "sync" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/log" + suave "github.com/ethereum/go-ethereum/suave/core" +) + +var _ suave.ConfidentialStoreBackend = &LocalConfidentialStore{} + +type LocalConfidentialStore struct { + lock sync.Mutex + bids map[suave.BidId]suave.Bid + dataMap map[string][]byte + index map[string][]suave.BidId +} + +func NewLocalConfidentialStore() *LocalConfidentialStore { + return &LocalConfidentialStore{ + bids: make(map[suave.BidId]suave.Bid), + dataMap: make(map[string][]byte), + index: make(map[string][]suave.BidId), + } +} + +func (l *LocalConfidentialStore) Start() error { + return nil +} + +func (l *LocalConfidentialStore) Stop() error { + return nil +} + +func (l *LocalConfidentialStore) InitializeBid(bid suave.Bid) error { + l.lock.Lock() + defer l.lock.Unlock() + + _, found := l.bids[bid.Id] + if found { + return suave.ErrBidAlreadyPresent + } + + l.bids[bid.Id] = bid + + // index the bid by (protocol, block number) + indexKey := fmt.Sprintf("protocol-%s-bn-%d", bid.Version, bid.DecryptionCondition) + bidIds := l.index[indexKey] + bidIds = append(bidIds, bid.Id) + l.index[indexKey] = bidIds + + return nil +} + +func (l *LocalConfidentialStore) Store(bid suave.Bid, caller common.Address, key string, value []byte) (suave.Bid, error) { + l.lock.Lock() + defer l.lock.Unlock() + + l.dataMap[fmt.Sprintf("%x-%s", bid.Id, key)] = append(make([]byte, 0, len(value)), value...) + + defer log.Trace("CSSW", "caller", caller, "key", key, "value", value, "stored", l.dataMap[fmt.Sprintf("%x-%s", bid.Id, key)]) + return bid, nil +} + +func (l *LocalConfidentialStore) Retrieve(bid suave.Bid, caller common.Address, key string) ([]byte, error) { + l.lock.Lock() + defer l.lock.Unlock() + + data, found := l.dataMap[fmt.Sprintf("%x-%s", bid.Id, key)] + if !found { + return []byte{}, fmt.Errorf("data for key %s not found", key) + } + + log.Trace("CSRW", "caller", caller, "key", key, "data", data) + return append(make([]byte, 0, len(data)), data...), nil +} + +func (l *LocalConfidentialStore) FetchBidById(bidId suave.BidId) (suave.Bid, error) { + bid, found := l.bids[bidId] + if !found { + return suave.Bid{}, errors.New("bid not found") + } + + return bid, nil +} + +func (l *LocalConfidentialStore) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid { + indexKey := fmt.Sprintf("protocol-%s-bn-%d", namespace, blockNumber) + bidIDs, ok := l.index[indexKey] + if !ok { + return nil + } + + res := []suave.Bid{} + for _, id := range bidIDs { + bid, err := l.FetchBidById(id) + if err != nil { + continue + } + res = append(res, bid) + } + + return res +} diff --git a/suave/backends/local_store_backend_test.go b/suave/backends/local_store_backend_test.go new file mode 100644 index 0000000000..9da3bb1e35 --- /dev/null +++ b/suave/backends/local_store_backend_test.go @@ -0,0 +1,10 @@ +package backends + +import ( + "testing" +) + +func TestLocal_StoreSuite(t *testing.T) { + store := NewLocalConfidentialStore() + testBackendStore(t, store) +} diff --git a/suave/backends/redis_store_backend.go b/suave/backends/redis_store_backend.go index a005e424fa..d108ca7909 100644 --- a/suave/backends/redis_store_backend.go +++ b/suave/backends/redis_store_backend.go @@ -15,6 +15,8 @@ import ( "github.com/go-redis/redis/v8" ) +var _ suave.ConfidentialStoreBackend = &RedisStoreBackend{} + var ( formatRedisBidKey = func(bidId suave.BidId) string { return fmt.Sprintf("bid-%x", bidId) @@ -35,10 +37,6 @@ type RedisStoreBackend struct { local *miniredis.Miniredis } -func NewLocalConfidentialStore() *RedisStoreBackend { - return NewRedisStoreBackend("") -} - func NewRedisStoreBackend(redisUri string) *RedisStoreBackend { r := &RedisStoreBackend{ cancel: nil, From ee72ced373855059d6d5c25b975a8e481a3ffbda Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Mon, 2 Oct 2023 13:08:36 +0200 Subject: [PATCH 4/5] Add locks --- suave/backends/local_store_backend.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/suave/backends/local_store_backend.go b/suave/backends/local_store_backend.go index cb9ff390ae..3e1727e9df 100644 --- a/suave/backends/local_store_backend.go +++ b/suave/backends/local_store_backend.go @@ -79,6 +79,9 @@ func (l *LocalConfidentialStore) Retrieve(bid suave.Bid, caller common.Address, } func (l *LocalConfidentialStore) FetchBidById(bidId suave.BidId) (suave.Bid, error) { + l.lock.Lock() + defer l.lock.Unlock() + bid, found := l.bids[bidId] if !found { return suave.Bid{}, errors.New("bid not found") @@ -88,6 +91,9 @@ func (l *LocalConfidentialStore) FetchBidById(bidId suave.BidId) (suave.Bid, err } func (l *LocalConfidentialStore) FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) []suave.Bid { + l.lock.Lock() + defer l.lock.Unlock() + indexKey := fmt.Sprintf("protocol-%s-bn-%d", namespace, blockNumber) bidIDs, ok := l.index[indexKey] if !ok { From 3241e7762e32c0386a74cff4c645b8d2dc281456 Mon Sep 17 00:00:00 2001 From: Ferran Borreguero Date: Mon, 2 Oct 2023 15:53:59 +0200 Subject: [PATCH 5/5] Avoid deadlock --- suave/backends/local_store_backend.go | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/suave/backends/local_store_backend.go b/suave/backends/local_store_backend.go index 3e1727e9df..6ed97cd7b7 100644 --- a/suave/backends/local_store_backend.go +++ b/suave/backends/local_store_backend.go @@ -102,11 +102,10 @@ func (l *LocalConfidentialStore) FetchBidsByProtocolAndBlock(blockNumber uint64, res := []suave.Bid{} for _, id := range bidIDs { - bid, err := l.FetchBidById(id) - if err != nil { - continue + bid, found := l.bids[id] + if found { + res = append(res, bid) } - res = append(res, bid) } return res