Skip to content

Commit

Permalink
update per CR
Browse files Browse the repository at this point in the history
  • Loading branch information
tsachiherman committed Oct 9, 2024
1 parent e3855fe commit 9c74334
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 42 deletions.
17 changes: 10 additions & 7 deletions api/jsonrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const (

var _ api.HandlerFactory[api.VM] = (*JSONRPCServerFactory)(nil)

var (
errSimulateZeroActions = errors.New("simulateAction expects at least a single action, none found")
errTransactionExtraBytes = errors.New("transaction has extra bytes")
)

type JSONRPCServerFactory struct{}

func (JSONRPCServerFactory) New(vm api.VM) (api.Handler, error) {
Expand Down Expand Up @@ -96,7 +101,7 @@ func (j *JSONRPCServer) SubmitTx(
return fmt.Errorf("%w: unable to unmarshal on public service", err)
}
if !rtx.Empty() {
return errors.New("tx has extra bytes")
return errTransactionExtraBytes
}
if err := tx.Verify(ctx); err != nil {
return err
Expand Down Expand Up @@ -263,22 +268,21 @@ func (j *JSONRPCServer) SimulateActions(
return err
}
if !actionsReader.Empty() {
return errors.New("tx has extra bytes")
return errTransactionExtraBytes
}
actions = append(actions, action)
}
if len(actions) == 0 {
return errors.New("simulateAction expects at least a single action, none found")
return errSimulateZeroActions
}
currentState, err := j.vm.ImmutableState(ctx)
if err != nil {
return err
}

recorder := state.NewRecorder(currentState)

currentTime := time.Now().UnixMilli()
for _, action := range actions {
recorder := state.NewRecorder(currentState)
actionOutput, err := action.Execute(ctx, j.vm.Rules(currentTime), recorder, currentTime, args.Actor, ids.Empty)

var actionResult SimulateActionResult
Expand All @@ -295,8 +299,7 @@ func (j *JSONRPCServer) SimulateActions(
}
actionResult.StateKeys = recorder.GetStateKeys()
reply.ActionResults = append(reply.ActionResults, actionResult)
// create another recorder to recored the next action.
recorder = state.NewRecorder(recorder)
currentState = recorder
}
return nil
}
6 changes: 0 additions & 6 deletions examples/vmwithcontracts/actions/call.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,3 @@ type Result struct {
func (*Result) GetTypeID() uint8 {
return mconsts.ResultOutputID
}

// Size is the number of bytes it takes to represent this [Action]. This is used to preallocate
// memory during encoding and to charge bandwidth fees.
func (r *Result) Size() int {
return consts.Uint64Len + consts.Uint32Len + len(r.Value)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"github.com/ava-labs/hypersdk/utils"
)

var errUnexpectedSimulateActionsOutput = errors.New("returned output from SimulateActions was not actions.Result")

var actionCmd = &cobra.Command{
Use: "action",
RunE: func(*cobra.Command, []string) error {
Expand Down Expand Up @@ -164,7 +166,7 @@ var callCmd = &cobra.Command{
}
simulationResult, ok := simulationResultOutput.(*actions.Result)
if !ok {
return errors.New("returned output from SimulateActions was not actions.Result")
return errUnexpectedSimulateActionsOutput
}

action.SpecifiedStateKeys = make([]actions.StateKeyPermission, 0, len(actionSimulationResult.StateKeys))
Expand Down
4 changes: 2 additions & 2 deletions state/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func (k Keys) MarshalJSON() ([]byte, error) {
return json.Marshal(keysJSON)
}

func (k Keys) UnmarshalJSON(b []byte) error {
func (k *Keys) UnmarshalJSON(b []byte) error {
var keysJSON keysJSON
if err := json.Unmarshal(b, &keysJSON); err != nil {
return err
Expand All @@ -84,7 +84,7 @@ func (k Keys) UnmarshalJSON(b []byte) error {
if err != nil {
return err
}
k[string(key)] = Permissions(perm)
(*k)[string(key)] = Permissions(perm)
}
}
return nil
Expand Down
2 changes: 1 addition & 1 deletion state/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,4 +180,4 @@ func TestKeysMarshalingFuzz(t *testing.T) {
require.NoError(decodedKeys.UnmarshalJSON(bytes))
require.True(keys.compare(decodedKeys))
}
}
}
28 changes: 15 additions & 13 deletions state/recorder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
// The Recorder struct wraps an [Immutable] state object and tracks the permissions used
// against the various keys. The Recorder struct implements the [Mutable] interface, allowing
// it to act as a direct replacement for a database view.
// The Recorder struct maintain the same semantics as tstate_view in regards to the various
// The Recorder struct maintains the same semantics as TStateView in regards to the various
// required access permissions.
type Recorder struct {
// State is the underlying [Immutable] object
Expand All @@ -28,33 +28,34 @@ func NewRecorder(db Immutable) *Recorder {
return &Recorder{state: db, changedValues: map[string][]byte{}, stateKeys: map[string][]byte{}, keys: Keys{}}
}

func (r *Recorder) checkState(ctx context.Context, key []byte) error {
if _, has := r.stateKeys[string(key)]; has {
return nil
func (r *Recorder) checkState(ctx context.Context, key []byte) ([]byte, error) {
if val, has := r.stateKeys[string(key)]; has {
return val, nil
}
value, err := r.state.GetValue(ctx, key)
if err == nil {
// no error, key found.
r.stateKeys[string(key)] = value
return nil
return value, nil
}

if errors.Is(err, database.ErrNotFound) {
r.stateKeys[string(key)] = nil
err = nil
}
return err
return nil, err
}

func (r *Recorder) Insert(ctx context.Context, key []byte, value []byte) error {
stringKey := string(key)

if err := r.checkState(ctx, key); err != nil {
var stateKeyVal []byte
var err error
if stateKeyVal, err = r.checkState(ctx, key); err != nil {
return err
}
stateKeyVal, inStateKeys := r.stateKeys[stringKey]

if inStateKeys && stateKeyVal != nil {
if stateKeyVal != nil {
// underlying storage already has that key.
r.keys[stringKey] |= Write
} else {
Expand All @@ -77,7 +78,9 @@ func (r *Recorder) Remove(_ context.Context, key []byte) error {
func (r *Recorder) GetValue(ctx context.Context, key []byte) (value []byte, err error) {
stringKey := string(key)

if err := r.checkState(ctx, key); err != nil {
var stateKeyVal []byte

if stateKeyVal, err = r.checkState(ctx, key); err != nil {
return nil, err
}
r.keys[stringKey] |= Read
Expand All @@ -87,11 +90,10 @@ func (r *Recorder) GetValue(ctx context.Context, key []byte) (value []byte, err
}
return value, nil
}
value = r.stateKeys[stringKey]
if value == nil { // no such key exist.
if stateKeyVal == nil { // no such key exist.
return nil, database.ErrNotFound
}
return value, nil
return stateKeyVal, nil
}

func (r *Recorder) GetStateKeys() Keys {
Expand Down
23 changes: 11 additions & 12 deletions state/recorder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,18 @@ import (
"github.com/ava-labs/avalanchego/database"
"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/keys"
"github.com/ava-labs/hypersdk/state"
"github.com/ava-labs/hypersdk/state/tstate"
)

func randomNewKey() []byte {
randNewKey := make([]byte, 32)
randNewKey := make([]byte, 30, 32)
_, err := rand.Read(randNewKey)
if err != nil {
panic(err)
}
randNewKey[30] = 0
randNewKey[31] = 1
return randNewKey
return keys.EncodeChunks(randNewKey, 1)
}

func randomizeView(tstate *tstate.TState, keyCount int) (*tstate.TStateView, [][]byte, map[string]state.Permissions, map[string][]byte) {
Expand Down Expand Up @@ -55,7 +54,7 @@ func TestRecorderInnerFuzz(t *testing.T) {
removedKeys map[string]bool
)

randomKey := func() []byte {
pickExistingKeyAtRandom := func() []byte {
randKey := make([]byte, 1)
_, err := rand.Read(randKey)
require.NoError(err)
Expand All @@ -78,7 +77,7 @@ func TestRecorderInnerFuzz(t *testing.T) {
require.NoError(err)
switch op[0] % 6 {
case 0: // insert into existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()
err := recorder.Insert(context.Background(), randKey, []byte{1, 2, 3, 4})
require.NoError(err)
require.True(recorder.GetStateKeys()[string(randKey)].Has(state.Write))
Expand All @@ -91,7 +90,7 @@ func TestRecorderInnerFuzz(t *testing.T) {
require.True(recorder.GetStateKeys()[string(randNewKey)].Has(state.Allocate | state.Write))
keys = append(keys, randNewKey)
case 2: // remove existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()
err := recorder.Remove(context.Background(), randKey)
require.NoError(err)
removedKeys[string(randKey)] = true
Expand All @@ -102,7 +101,7 @@ func TestRecorderInnerFuzz(t *testing.T) {
require.NoError(err)
require.True(recorder.GetStateKeys()[string(randKey)].Has(state.Write))
case 4: // get value of existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()
val, err := recorder.GetValue(context.Background(), randKey)
require.NoError(err)
require.NotEmpty(val)
Expand Down Expand Up @@ -143,7 +142,7 @@ func TestRecorderSideBySideFuzz(t *testing.T) {
storage map[string][]byte
)

randomKey := func() []byte {
pickExistingKeyAtRandom := func() []byte {
randKey := make([]byte, 1)
_, err := rand.Read(randKey)
require.NoError(err)
Expand Down Expand Up @@ -173,7 +172,7 @@ func TestRecorderSideBySideFuzz(t *testing.T) {
require.NoError(err)
switch op[0] % 6 {
case 0: // insert into existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()
randVal := randomValue()

err := recorder.Insert(context.Background(), randKey, randVal)
Expand All @@ -197,7 +196,7 @@ func TestRecorderSideBySideFuzz(t *testing.T) {

keys = append(keys, randNewKey)
case 2: // remove existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()

err := recorder.Remove(context.Background(), randKey)
require.NoError(err)
Expand All @@ -219,7 +218,7 @@ func TestRecorderSideBySideFuzz(t *testing.T) {
err = stateView.Remove(context.Background(), randKey)
require.NoError(err)
case 4: // get value of existing entry
randKey := randomKey()
randKey := pickExistingKeyAtRandom()

val, err := recorder.GetValue(context.Background(), randKey)
require.NoError(err)
Expand Down

0 comments on commit 9c74334

Please sign in to comment.