Skip to content

Commit

Permalink
Simulate a chain of actions (#1635)
Browse files Browse the repository at this point in the history
  • Loading branch information
containerman17 authored Oct 9, 2024
1 parent fee360f commit b5407c9
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 54 deletions.
22 changes: 13 additions & 9 deletions api/jsonrpc/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
args,
resp,
)
Expand All @@ -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 {
Expand Down
98 changes: 53 additions & 45 deletions api/jsonrpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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)
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 {
// 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)
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,
)
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
}

0 comments on commit b5407c9

Please sign in to comment.