-
Notifications
You must be signed in to change notification settings - Fork 121
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Simulate a chain of actions #1635
Changes from all commits
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 |
---|---|---|
|
@@ -194,21 +194,25 @@ func (cli *JSONRPCClient) GetABI(ctx context.Context) (abi.ABI, error) { | |
return resp.ABI, err | ||
} | ||
|
||
func (cli *JSONRPCClient) Execute(ctx context.Context, actor codec.Address, action chain.Action) ([]byte, error) { | ||
actionBytes, err := chain.MarshalTyped(action) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal action: %w", err) | ||
func (cli *JSONRPCClient) Execute(ctx context.Context, actor codec.Address, actions []chain.Action) ([][]byte, error) { | ||
actionsMarshaled := make([][]byte, 0) | ||
for _, action := range actions { | ||
actionBytes, err := chain.MarshalTyped(action) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to marshal action: %w", err) | ||
} | ||
actionsMarshaled = append(actionsMarshaled, actionBytes) | ||
} | ||
|
||
args := &ExecuteActionArgs{ | ||
Actor: actor, | ||
Action: actionBytes, | ||
Actor: actor, | ||
Actions: actionsMarshaled, | ||
} | ||
|
||
resp := new(ExecuteActionReply) | ||
err = cli.requester.SendRequest( | ||
err := cli.requester.SendRequest( | ||
ctx, | ||
"executeAction", | ||
"execute", | ||
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 rename to |
||
args, | ||
resp, | ||
) | ||
|
@@ -219,7 +223,7 @@ func (cli *JSONRPCClient) Execute(ctx context.Context, actor codec.Address, acti | |
return nil, fmt.Errorf("failed to execute action: %s", resp.Error) | ||
} | ||
|
||
return resp.Output, nil | ||
return resp.Outputs, nil | ||
} | ||
|
||
func Wait(ctx context.Context, interval time.Duration, check func(ctx context.Context) (bool, error)) error { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -157,13 +157,13 @@ func (j *JSONRPCServer) GetABI(_ *http.Request, _ *GetABIArgs, reply *GetABIRepl | |
} | ||
|
||
type ExecuteActionArgs struct { | ||
Actor codec.Address `json:"actor"` | ||
Action []byte `json:"action"` | ||
Actor codec.Address `json:"actor"` | ||
Actions [][]byte `json:"actions"` | ||
} | ||
|
||
type ExecuteActionReply struct { | ||
Output []byte `json:"output"` | ||
Error string `json:"error"` | ||
Outputs [][]byte `json:"outputs"` | ||
Error string `json:"error"` | ||
} | ||
|
||
func (j *JSONRPCServer) Execute( | ||
|
@@ -175,58 +175,66 @@ func (j *JSONRPCServer) Execute( | |
defer span.End() | ||
|
||
actionRegistry := j.vm.ActionRegistry() | ||
action, err := (*actionRegistry).Unmarshal(codec.NewReader(args.Action, len(args.Action))) | ||
if err != nil { | ||
return fmt.Errorf("failed to unmashal action: %w", err) | ||
actions := make([]chain.Action, 0) | ||
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. same comment on pre-allocating where we already know the length of |
||
for _, action := range args.Actions { | ||
action, err := (*actionRegistry).Unmarshal(codec.NewReader(action, len(action))) | ||
if err != nil { | ||
return fmt.Errorf("failed to unmashal action: %w", err) | ||
} | ||
actions = append(actions, action) | ||
} | ||
|
||
now := time.Now().UnixMilli() | ||
|
||
// Get expected state keys | ||
stateKeysWithPermissions := action.StateKeys(args.Actor) | ||
storage := make(map[string][]byte) | ||
ts := tstate.New(1) | ||
|
||
// flatten the map to a slice of keys | ||
storageKeysToRead := make([][]byte, 0) | ||
for key := range stateKeysWithPermissions { | ||
storageKeysToRead = append(storageKeysToRead, []byte(key)) | ||
} | ||
for _, action := range actions { | ||
aaronbuchwald marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Get expected state keys | ||
stateKeysWithPermissions := action.StateKeys(args.Actor) | ||
|
||
storage := make(map[string][]byte) | ||
values, errs := j.vm.ReadState(ctx, storageKeysToRead) | ||
for _, err := range errs { | ||
if err != nil && !errors.Is(err, database.ErrNotFound) { | ||
return fmt.Errorf("failed to read state: %w", err) | ||
// flatten the map to a slice of keys | ||
storageKeysToRead := make([][]byte, 0) | ||
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. same comment on pre-allocating where we already know the size of |
||
for key := range stateKeysWithPermissions { | ||
storageKeysToRead = append(storageKeysToRead, []byte(key)) | ||
} | ||
} | ||
for i, value := range values { | ||
if value == nil { | ||
continue | ||
|
||
values, errs := j.vm.ReadState(ctx, storageKeysToRead) | ||
for _, err := range errs { | ||
if err != nil && !errors.Is(err, database.ErrNotFound) { | ||
return fmt.Errorf("failed to read state: %w", err) | ||
} | ||
} | ||
for i, value := range values { | ||
if value == nil { | ||
continue | ||
} | ||
storage[string(storageKeysToRead[i])] = value | ||
} | ||
storage[string(storageKeysToRead[i])] = value | ||
} | ||
|
||
ts := tstate.New(1) | ||
tsv := ts.NewView(stateKeysWithPermissions, storage) | ||
|
||
output, err := action.Execute( | ||
ctx, | ||
j.vm.Rules(now), | ||
tsv, | ||
now, | ||
args.Actor, | ||
ids.Empty, | ||
) | ||
if err != nil { | ||
reply.Error = fmt.Sprintf("failed to execute action: %s", err) | ||
return nil | ||
} | ||
tsv := ts.NewView(stateKeysWithPermissions, storage) | ||
|
||
output, err := action.Execute( | ||
ctx, | ||
j.vm.Rules(now), | ||
tsv, | ||
now, | ||
args.Actor, | ||
ids.Empty, | ||
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. This may cause issues for actions that rely on the Could we prevent this by using |
||
) | ||
if err != nil { | ||
reply.Error = fmt.Sprintf("failed to execute action: %s", err) | ||
return nil | ||
} | ||
|
||
encodedOutput, err := chain.MarshalTyped(output) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal output: %w", err) | ||
} | ||
tsv.Commit() | ||
|
||
reply.Output = encodedOutput | ||
encodedOutput, err := chain.MarshalTyped(output) | ||
if err != nil { | ||
return fmt.Errorf("failed to marshal output: %w", err) | ||
} | ||
|
||
reply.Outputs = append(reply.Outputs, encodedOutput) | ||
} | ||
return nil | ||
} |
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 pre-allocate where we already know the length of the slice? Same comment throughout