Skip to content
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

feature: Add initial support for runtime rofl transactions #812

Merged
merged 1 commit into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changelog/812.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
feature: Add support for runtime rofl transactions

New runtime transactions:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not an ask for this PR, but we should think about adding another e2e regression suite that encompasses rofl/sapphire/consensusaccount txs and the rest of the new features being added :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, opened #826


- `rofl.Create`, `rofl.Update`, `rofl.Remove`, `rofl.Register`

New runtime events:

- `rofl.app_created`, `rofl.app_updated`, `rofl.app_removed`
37 changes: 37 additions & 0 deletions analyzer/runtime/decode_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/consensusaccounts"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/core"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/evm"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"

"github.com/oasisprotocol/nexus/storage/oasis/nodeapi"
)
Expand Down Expand Up @@ -145,6 +146,42 @@ func DecodeEVMEvent(event *nodeapi.RuntimeEvent) ([]evm.Event, error) {
return events, nil
}

func DecodeRoflEvent(event *nodeapi.RuntimeEvent) ([]rofl.Event, error) {
if event.Module != rofl.ModuleName {
return nil, nil
}
var events []rofl.Event
switch event.Code {
case rofl.AppCreatedEventCode:
var evs []*rofl.AppCreatedEvent
if err := unmarshalSingleOrArray(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode rofl app created event value: %w", err)
}
for _, ev := range evs {
events = append(events, rofl.Event{AppCreated: ev})
}
case rofl.AppUpdatedEventCode:
var evs []*rofl.AppUpdatedEvent
if err := unmarshalSingleOrArray(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode rofl app updated event value: %w", err)
}
for _, ev := range evs {
events = append(events, rofl.Event{AppUpdated: ev})
}
case rofl.AppRemovedEventCode:
var evs []*rofl.AppRemovedEvent
if err := unmarshalSingleOrArray(event.Value, &evs); err != nil {
return nil, fmt.Errorf("decode rofl app removed event value: %w", err)
}
for _, ev := range evs {
events = append(events, rofl.Event{AppRemoved: ev})
}
default:
return nil, fmt.Errorf("invalid rofl event code: %v", event.Code)
}
return events, nil
}

// unmarshalSingleOrArray tries to interpret `data` as an array of `T`.
// Failing that, it interprets it as a single `T`, and returns a slice
// of size 1 containing that `T`.
Expand Down
48 changes: 48 additions & 0 deletions analyzer/runtime/extract.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/consensusaccounts"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/core"
sdkEVM "github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/evm"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"
sdkTypes "github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"

"github.com/oasisprotocol/nexus/analyzer/evmabi"
Expand Down Expand Up @@ -109,6 +110,7 @@ type ScopedSdkEvent struct {
Accounts *accounts.Event
ConsensusAccounts *consensusaccounts.Event
EVM *sdkEVM.Event
Rofl *rofl.Event
}

type TokenChangeKey struct {
Expand Down Expand Up @@ -505,6 +507,25 @@ func ExtractRound(blockHeader nodeapi.RuntimeBlockHeader, txrs []nodeapi.Runtime
// TODO: maybe parse known token methods (ERC-20 etc)
return nil
},
RoflCreate: func(body *rofl.Create) error {
blockTransactionData.Body = body
return nil
},
RoflUpdate: func(body *rofl.Update) error {
blockTransactionData.Body = body
if _, err = addresses.RegisterRelatedSdkAddress(blockTransactionData.RelatedAccountAddresses, body.Admin); err != nil {
return fmt.Errorf("rofl.Update admin address: %w", err)
}
return nil
},
RoflRemove: func(body *rofl.Remove) error {
blockTransactionData.Body = body
return nil
},
RoflRegister: func(body *rofl.Register) error {
blockTransactionData.Body = body
return nil
},
UnknownMethod: func(methodName string) error {
logger.Warn("unknown tx method, skipping tx-specific analysis", "tx_method", methodName)
return nil
Expand Down Expand Up @@ -1359,6 +1380,33 @@ func extractEvents(blockData *BlockData, relatedAccountAddresses map[apiTypes.Ad
extractedEvents = append(extractedEvents, &eventData)
return nil
},
Rofl: func(event *rofl.Event) error {
if event.AppCreated != nil {
eventData := EventData{
Type: apiTypes.RuntimeEventTypeRoflAppCreated,
Body: event.AppCreated,
WithScope: ScopedSdkEvent{Rofl: event},
}
extractedEvents = append(extractedEvents, &eventData)
}
if event.AppRemoved != nil {
eventData := EventData{
Type: apiTypes.RuntimeEventTypeRoflAppRemoved,
Body: event.AppRemoved,
WithScope: ScopedSdkEvent{Rofl: event},
}
extractedEvents = append(extractedEvents, &eventData)
}
if event.AppUpdated != nil {
eventData := EventData{
Type: apiTypes.RuntimeEventTypeRoflAppUpdated,
Body: event.AppUpdated,
WithScope: ScopedSdkEvent{Rofl: event},
}
extractedEvents = append(extractedEvents, &eventData)
}
return nil
},
}); err != nil {
return nil, err
}
Expand Down
57 changes: 57 additions & 0 deletions analyzer/runtime/visitors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/consensusaccounts"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/core"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/evm"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/rofl"
sdkTypes "github.com/oasisprotocol/oasis-sdk/client-sdk/go/types"

"github.com/oasisprotocol/nexus/analyzer/evmabi"
Expand All @@ -27,6 +28,10 @@ type CallHandler struct {
ConsensusAccountsUndelegate func(body *consensusaccounts.Undelegate) error
EVMCreate func(body *evm.Create, ok *[]byte) error
EVMCall func(body *evm.Call, ok *[]byte) error
RoflCreate func(body *rofl.Create) error
RoflUpdate func(body *rofl.Update) error
RoflRemove func(body *rofl.Remove) error
RoflRegister func(body *rofl.Register) error
UnknownMethod func(methodName string) error // Invoked for a tx call that doesn't map to any of the above method names.
}

Expand Down Expand Up @@ -121,6 +126,46 @@ func VisitCall(call *sdkTypes.Call, result *sdkTypes.CallResult, handler *CallHa
return fmt.Errorf("evm call: %w", err)
}
}
case "rofl.Create":
if handler.RoflCreate != nil {
var body rofl.Create
if err := cbor.Unmarshal(call.Body, &body); err != nil {
return fmt.Errorf("unmarshal rofl create: %w", err)
}
if err := handler.RoflCreate(&body); err != nil {
return fmt.Errorf("rofl create: %w", err)
}
}
case "rofl.Update":
if handler.RoflUpdate != nil {
var body rofl.Update
if err := cbor.Unmarshal(call.Body, &body); err != nil {
return fmt.Errorf("unmarshal rofl update: %w", err)
}
if err := handler.RoflUpdate(&body); err != nil {
return fmt.Errorf("rofl update: %w", err)
}
}
Comment on lines +129 to +148
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any relevant information in the CallResult for rofl transactions? Or is it left for a future ticket?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"rofl.Create" has App ID, others are empty. But we don't have anything to do with it at the moment, will leave it as a followup #807

case "rofl.Remove":
if handler.RoflRemove != nil {
var body rofl.Remove
if err := cbor.Unmarshal(call.Body, &body); err != nil {
return fmt.Errorf("unmarshal rofl remove: %w", err)
}
if err := handler.RoflRemove(&body); err != nil {
return fmt.Errorf("rofl remove: %w", err)
}
}
case "rofl.Register":
if handler.RoflRegister != nil {
var body rofl.Register
if err := cbor.Unmarshal(call.Body, &body); err != nil {
return fmt.Errorf("unmarshal rofl register: %w", err)
}
if err := handler.RoflRegister(&body); err != nil {
return fmt.Errorf("rofl register: %w", err)
}
}
default:
if handler.UnknownMethod != nil {
return handler.UnknownMethod(string(call.Method))
Expand All @@ -134,6 +179,7 @@ type SdkEventHandler struct {
Accounts func(event *accounts.Event) error
ConsensusAccounts func(event *consensusaccounts.Event) error
EVM func(event *evm.Event) error
Rofl func(event *rofl.Event) error
}

func VisitSdkEvent(event *nodeapi.RuntimeEvent, handler *SdkEventHandler) error {
Expand Down Expand Up @@ -181,6 +227,17 @@ func VisitSdkEvent(event *nodeapi.RuntimeEvent, handler *SdkEventHandler) error
}
}
}
if handler.Rofl != nil {
roflEvents, err := DecodeRoflEvent(event)
if err != nil {
return fmt.Errorf("decode rofl: %w", err)
}
for i := range roflEvents {
if err = handler.Rofl(&roflEvents[i]); err != nil {
return fmt.Errorf("decoded event %d rofl: %w", i, err)
}
}
}
return nil
}

Expand Down
7 changes: 7 additions & 0 deletions api/spec/v1.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2779,6 +2779,9 @@ components:
- consensus_accounts.undelegate_done
- core.gas_used
- evm.log
- rofl.app_created
- rofl.app_updated
- rofl.app_removed
example: *runtime_event_type_1

EvmAbiParam:
Expand Down Expand Up @@ -3009,6 +3012,10 @@ components:
- "consensus.Undelegate"
- "evm.Create"
- "evm.Call"
- "rofl.Create"
- "rofl.Update"
- "rofl.Remove"
- "rofl.Register"
May be null if the transaction was malformed or encrypted.
example: "evm.Call"
body:
Expand Down
Loading
Loading