Skip to content

Commit

Permalink
Add barebones builder with mempool validation facilities
Browse files Browse the repository at this point in the history
  • Loading branch information
omerfirmak committed Dec 8, 2023
1 parent 63f66ac commit caab622
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 0 deletions.
68 changes: 68 additions & 0 deletions builder/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package builder

import (
"errors"

"github.com/NethermindEth/juno/blockchain"
"github.com/NethermindEth/juno/core"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/db"
"github.com/NethermindEth/juno/mempool"
"github.com/NethermindEth/juno/utils"
"github.com/NethermindEth/juno/vm"
)

type Builder struct {
ownAddress felt.Felt

bc *blockchain.Blockchain
vm vm.VM

log utils.Logger
}

func New(ownAddr *felt.Felt, bc *blockchain.Blockchain, builderVM vm.VM, log utils.Logger) *Builder {
return &Builder{
ownAddress: *ownAddr,

bc: bc,
vm: builderVM,
}
}

// ValidateAgainstPendingState validates a user transaction against the pending state
// only hard-failures result in an error, reverts are not reported back to caller
func (b *Builder) ValidateAgainstPendingState(userTxn *mempool.BroadcastedTransaction) error {
declaredClasses := []core.Class{}
if userTxn.DeclaredClass != nil {
declaredClasses = []core.Class{userTxn.DeclaredClass}
}

nextHeight := uint64(0)
if height, err := b.bc.Height(); err == nil {
nextHeight = height + 1
} else if err != nil && !errors.Is(err, db.ErrKeyNotFound) {
return err
}

Check warning on line 46 in builder/builder.go

View check run for this annotation

Codecov / codecov/patch

builder/builder.go#L45-L46

Added lines #L45 - L46 were not covered by tests

pendingBlock, err := b.bc.Pending()
if err != nil {
return err
}

Check warning on line 51 in builder/builder.go

View check run for this annotation

Codecov / codecov/patch

builder/builder.go#L50-L51

Added lines #L50 - L51 were not covered by tests

state, stateCloser, err := b.bc.PendingState()
if err != nil {
return err
}

Check warning on line 56 in builder/builder.go

View check run for this annotation

Codecov / codecov/patch

builder/builder.go#L55-L56

Added lines #L55 - L56 were not covered by tests

defer func() {
if err = stateCloser(); err != nil {
b.log.Errorw("closing state in ValidateAgainstPendingState", "err", err)
}

Check warning on line 61 in builder/builder.go

View check run for this annotation

Codecov / codecov/patch

builder/builder.go#L60-L61

Added lines #L60 - L61 were not covered by tests
}()

_, _, err = b.vm.Execute([]core.Transaction{userTxn.Transaction}, declaredClasses, nextHeight,
pendingBlock.Block.Timestamp, &b.ownAddress, state, b.bc.Network(), []*felt.Felt{},
false, false, false, pendingBlock.Block.GasPrice, pendingBlock.Block.GasPriceSTRK, false)
return err
}
63 changes: 63 additions & 0 deletions builder/builder_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package builder_test

import (
"context"
"errors"
"testing"

"github.com/NethermindEth/juno/blockchain"
"github.com/NethermindEth/juno/builder"
"github.com/NethermindEth/juno/clients/feeder"
"github.com/NethermindEth/juno/core"
"github.com/NethermindEth/juno/core/felt"
"github.com/NethermindEth/juno/db/pebble"
"github.com/NethermindEth/juno/mempool"
"github.com/NethermindEth/juno/mocks"
adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder"
"github.com/NethermindEth/juno/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)

func TestValidateAgainstPendingState(t *testing.T) {
testDB := pebble.NewMemTest(t)
mockCtrl := gomock.NewController(t)
mockVM := mocks.NewMockVM(mockCtrl)
bc := blockchain.New(testDB, utils.Integration, utils.NewNopZapLogger())
seqAddr := utils.HexToFelt(t, "0xDEADBEEF")
testBuilder := builder.New(seqAddr, bc, mockVM, utils.NewNopZapLogger())

client := feeder.NewTestClient(t, utils.Integration)
gw := adaptfeeder.New(client)

su, b, err := gw.StateUpdateWithBlock(context.Background(), 0)
require.NoError(t, err)

require.NoError(t, bc.StorePending(&blockchain.Pending{
Block: b,
StateUpdate: su,
}))

userTxn := mempool.BroadcastedTransaction{
Transaction: &core.InvokeTransaction{
TransactionHash: utils.HexToFelt(t, "0x1337"),
},
DeclaredClass: &core.Cairo0Class{
Program: "best program",
},
}

mockVM.EXPECT().Execute([]core.Transaction{userTxn.Transaction},
[]core.Class{userTxn.DeclaredClass}, uint64(0), b.Timestamp, seqAddr,
gomock.Any(), utils.Integration, []*felt.Felt{}, false, false,
false, b.GasPrice, b.GasPriceSTRK, false).Return(nil, nil, nil)
assert.NoError(t, testBuilder.ValidateAgainstPendingState(&userTxn))

require.NoError(t, bc.Store(b, &core.BlockCommitments{}, su, nil))
mockVM.EXPECT().Execute([]core.Transaction{userTxn.Transaction},
[]core.Class{userTxn.DeclaredClass}, uint64(1), b.Timestamp+1, seqAddr,
gomock.Any(), utils.Integration, []*felt.Felt{}, false, false,
false, b.GasPrice, b.GasPriceSTRK, false).Return(nil, nil, errors.New("oops"))
assert.EqualError(t, testBuilder.ValidateAgainstPendingState(&userTxn), "oops")
}

0 comments on commit caab622

Please sign in to comment.