-
Notifications
You must be signed in to change notification settings - Fork 115
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
add simulateTransaction endpoint #1610
Changes from 22 commits
45749b1
23c8b1d
65df47b
6fc64c9
693b7c0
0da1d84
1a2e340
8253c81
7d26831
75c07e6
a306b46
5379398
ff86ecf
f42b284
c08b8cf
793a6b0
7f3868e
5399ff3
c172c59
89a134d
f5d4dd8
e3855fe
9c74334
267e13b
b6bd4f2
e51d8fd
689d0ec
8f020d8
65c9c42
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -18,6 +18,7 @@ import ( | |||||
"github.com/ava-labs/hypersdk/codec" | ||||||
"github.com/ava-labs/hypersdk/consts" | ||||||
"github.com/ava-labs/hypersdk/fees" | ||||||
"github.com/ava-labs/hypersdk/state" | ||||||
"github.com/ava-labs/hypersdk/state/tstate" | ||||||
) | ||||||
|
||||||
|
@@ -230,3 +231,72 @@ func (j *JSONRPCServer) Execute( | |||||
|
||||||
return nil | ||||||
} | ||||||
|
||||||
type SimulatActionsArgs struct { | ||||||
Actions []codec.Bytes `json:"actions"` | ||||||
Actor codec.Address `json:"actor"` | ||||||
} | ||||||
|
||||||
type SimulateActionResult struct { | ||||||
Output codec.Bytes `json:"output"` | ||||||
StateKeys state.Keys `json:"stateKeys"` | ||||||
} | ||||||
|
||||||
type SimulateActionsReply struct { | ||||||
ActionResults []SimulateActionResult `json:"actionresults"` | ||||||
} | ||||||
|
||||||
func (j *JSONRPCServer) SimulateActions( | ||||||
req *http.Request, | ||||||
args *SimulatActionsArgs, | ||||||
reply *SimulateActionsReply, | ||||||
) error { | ||||||
ctx, span := j.vm.Tracer().Start(req.Context(), "JSONRPCServer.SimulateActions") | ||||||
defer span.End() | ||||||
|
||||||
actionRegistry := j.vm.ActionRegistry() | ||||||
var actions chain.Actions | ||||||
for _, actionBytes := range args.Actions { | ||||||
actionsReader := codec.NewReader(actionBytes, len(actionBytes)) | ||||||
action, err := (*actionRegistry).Unmarshal(actionsReader) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
if !actionsReader.Empty() { | ||||||
return errors.New("tx has extra bytes") | ||||||
} | ||||||
actions = append(actions, action) | ||||||
} | ||||||
if len(actions) == 0 { | ||||||
return errors.New("simulateAction expects at least a single action, none found") | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we move this error definition to a variable at the top of the file? Perhaps There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
} | ||||||
currentState, err := j.vm.ImmutableState(ctx) | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
|
||||||
recorder := state.NewRecorder(currentState) | ||||||
|
||||||
currentTime := time.Now().UnixMilli() | ||||||
for _, action := range actions { | ||||||
actionOutput, err := action.Execute(ctx, j.vm.Rules(currentTime), recorder, currentTime, args.Actor, ids.Empty) | ||||||
|
||||||
var actionResult SimulateActionResult | ||||||
if actionOutput == nil { | ||||||
actionResult.Output = []byte{} | ||||||
} else { | ||||||
actionResult.Output, err = chain.MarshalTyped(actionOutput) | ||||||
if err != nil { | ||||||
return fmt.Errorf("failed to marshal output: %w", err) | ||||||
} | ||||||
} | ||||||
if err != nil { | ||||||
return err | ||||||
} | ||||||
tsachiherman marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
actionResult.StateKeys = recorder.GetStateKeys() | ||||||
reply.ActionResults = append(reply.ActionResults, actionResult) | ||||||
// create another recorder to recored the next action. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||||||
recorder = state.NewRecorder(recorder) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit - is there a reason that we need to chain the recorders this way? It seems like this should be fine because each recorder just takes the place of Could we move creating the first recorder into the loop, so that the top of the loop has There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, done. |
||||||
} | ||||||
return nil | ||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,8 @@ package cmd | |
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/near/borsh-go" | ||
|
@@ -15,6 +17,7 @@ import ( | |
"github.com/ava-labs/hypersdk/cli/prompt" | ||
"github.com/ava-labs/hypersdk/codec" | ||
"github.com/ava-labs/hypersdk/examples/vmwithcontracts/actions" | ||
"github.com/ava-labs/hypersdk/examples/vmwithcontracts/vm" | ||
"github.com/ava-labs/hypersdk/utils" | ||
) | ||
|
||
|
@@ -141,18 +144,34 @@ var callCmd = &cobra.Command{ | |
ContractAddress: contractAddress, | ||
Value: amount, | ||
Function: function, | ||
Fuel: uint64(1000000000), | ||
} | ||
|
||
specifiedStateKeysSet, fuel, err := bcli.Simulate(ctx, *action, priv.Address) | ||
actionSimulationResults, err := cli.SimulateActions(ctx, chain.Actions{action}, priv.Address) | ||
if err != nil { | ||
return err | ||
} | ||
if len(actionSimulationResults) != 1 { | ||
return fmt.Errorf("unexpected number of returned actions. One action expected, %d returned", len(actionSimulationResults)) | ||
} | ||
actionSimulationResult := actionSimulationResults[0] | ||
|
||
rtx := codec.NewReader(actionSimulationResult.Output, len(actionSimulationResult.Output)) | ||
|
||
simulationResultOutput, err := (*vm.OutputParser).Unmarshal(rtx) | ||
if err != nil { | ||
return err | ||
} | ||
simulationResult, ok := simulationResultOutput.(*actions.Result) | ||
if !ok { | ||
return errors.New("returned output from SimulateActions was not actions.Result") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we move this error definition to the top of the file? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
|
||
action.SpecifiedStateKeys = make([]actions.StateKeyPermission, 0, len(specifiedStateKeysSet)) | ||
for key, value := range specifiedStateKeysSet { | ||
action.SpecifiedStateKeys = make([]actions.StateKeyPermission, 0, len(actionSimulationResult.StateKeys)) | ||
for key, value := range actionSimulationResult.StateKeys { | ||
action.SpecifiedStateKeys = append(action.SpecifiedStateKeys, actions.StateKeyPermission{Key: key, Permission: value}) | ||
} | ||
action.Fuel = fuel | ||
action.Fuel = simulationResult.ConsumedFuel | ||
|
||
// Confirm action | ||
cont, err := prompt.Continue() | ||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: can we fix the error message here and move the error definition to the top of the file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done