Skip to content

Commit

Permalink
Merge branch 'main' into separate-proposer-monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
aaronbuchwald committed Sep 19, 2024
2 parents dbd14c9 + 7a8bb2d commit e17f286
Show file tree
Hide file tree
Showing 61 changed files with 688 additions and 338 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Execute(
timestamp int64,
actor codec.Address,
actionID ids.ID,
) (outputs [][]byte, err error)
) (output codec.Typed, err error)
```

To provide performance out of the box, the `chain.Action` interface requires additional functions to provide state prefetching, pessimistic concurrency control, and multi-dimensional fees.
Expand Down
52 changes: 35 additions & 17 deletions abi/abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import (
)

type ABI struct {
Actions []Action `serialize:"true" json:"actions"`
Types []Type `serialize:"true" json:"types"`
Actions []TypedStruct `serialize:"true" json:"actions"`
Outputs []TypedStruct `serialize:"true" json:"outputs"`
Types []Type `serialize:"true" json:"types"`
}

var _ codec.Typed = (*ABI)(nil)
Expand All @@ -29,24 +30,25 @@ type Field struct {
Type string `serialize:"true" json:"type"`
}

type Action struct {
ID uint8 `serialize:"true" json:"id"`
Action string `serialize:"true" json:"action"`
type TypedStruct struct {
ID uint8 `serialize:"true" json:"id"`
Name string `serialize:"true" json:"name"`
}

type Type struct {
Name string `serialize:"true" json:"name"`
Fields []Field `serialize:"true" json:"fields"`
}

func NewABI(actions []codec.Typed) (ABI, error) {
vmActions := make([]Action, 0)
func NewABI(actions []codec.Typed, returnTypes []codec.Typed) (ABI, error) {
vmActions := make([]TypedStruct, 0)
vmOutputs := make([]TypedStruct, 0)
vmTypes := make([]Type, 0)
typesSet := set.Set[string]{}
typesAlreadyProcessed := set.Set[reflect.Type]{}

for _, action := range actions {
actionABI, typeABI, err := describeAction(action, typesAlreadyProcessed)
actionABI, typeABI, err := describeTypedStruct(action, typesAlreadyProcessed)
if err != nil {
return ABI{}, err
}
Expand All @@ -58,21 +60,37 @@ func NewABI(actions []codec.Typed) (ABI, error) {
}
}
}
return ABI{Actions: vmActions, Types: vmTypes}, nil

for _, returnType := range returnTypes {
outputABI, typeABI, err := describeTypedStruct(returnType, typesAlreadyProcessed)
if err != nil {
return ABI{}, err
}
vmOutputs = append(vmOutputs, outputABI)
for _, t := range typeABI {
if !typesSet.Contains(t.Name) {
vmTypes = append(vmTypes, t)
typesSet.Add(t.Name)
}
}
}

return ABI{Actions: vmActions, Outputs: vmOutputs, Types: vmTypes}, nil
}

// describeAction generates the Action and Types for a single action.
// describeTypedStruct generates the TypedStruct and Types for a single typed struct (action or output).
// It handles both struct and pointer types, and recursively processes nested structs.
// Does not support maps or interfaces - only standard go types, slices, arrays and structs
func describeAction(action codec.Typed, typesAlreadyProcessed set.Set[reflect.Type]) (Action, []Type, error) {
t := reflect.TypeOf(action)

func describeTypedStruct(typedStruct codec.Typed, typesAlreadyProcessed set.Set[reflect.Type]) (TypedStruct, []Type, error) {
t := reflect.TypeOf(typedStruct)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}

actionABI := Action{
ID: action.GetTypeID(),
Action: t.Name(),
typedStructABI := TypedStruct{
ID: typedStruct.GetTypeID(),
Name: t.Name(),
}

typesABI := make([]Type, 0)
Expand All @@ -95,7 +113,7 @@ func describeAction(action codec.Typed, typesAlreadyProcessed set.Set[reflect.Ty

fields, moreTypes, err := describeStruct(nextType)
if err != nil {
return Action{}, nil, err
return TypedStruct{}, nil, err
}

typesABI = append(typesABI, Type{
Expand All @@ -107,7 +125,7 @@ func describeAction(action codec.Typed, typesAlreadyProcessed set.Set[reflect.Ty
typesAlreadyProcessed.Add(nextType)
}

return actionABI, typesABI, nil
return typedStructABI, typesABI, nil
}

// describeStruct analyzes a struct type and returns its fields and any nested struct types it found
Expand Down
15 changes: 14 additions & 1 deletion abi/abi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package abi

import (
"encoding/json"
"testing"

"github.com/stretchr/testify/require"
Expand All @@ -23,6 +24,9 @@ func TestNewABI(t *testing.T) {
MockActionWithTransfer{},
MockActionWithTransferArray{},
Outer{},
ActionWithOutput{},
}, []codec.Typed{
ActionOutput{},
})
require.NoError(err)

Expand All @@ -35,11 +39,20 @@ func TestNewABI(t *testing.T) {
func TestGetABIofABI(t *testing.T) {
require := require.New(t)

actualABI, err := NewABI([]codec.Typed{ABI{}})
actualABI, err := NewABI([]codec.Typed{
ABI{},
}, []codec.Typed{})
require.NoError(err)

expectedABIJSON := mustReadFile(t, "testdata/abi.abi.json")
expectedABI := mustJSONParse[ABI](t, string(expectedABIJSON))

require.Equal(expectedABI, actualABI)
}

func mustJSONParse[T any](t *testing.T, jsonStr string) T {
var parsed T
err := json.Unmarshal([]byte(jsonStr), &parsed)
require.NoError(t, err, jsonStr)
return parsed
}
8 changes: 3 additions & 5 deletions abi/auto_marshal_abi_spec_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/stretchr/testify/require"

"github.com/ava-labs/hypersdk/chain"
"github.com/ava-labs/hypersdk/codec"
"github.com/ava-labs/hypersdk/consts"
)
Expand All @@ -30,12 +31,9 @@ func TestABIHash(t *testing.T) {
require.NoError(err)

// check hash and compare it to expected
writer := codec.NewWriter(0, consts.NetworkSizeLimit)
err = codec.LinearCodec.MarshalInto(abiFromFile, writer.Packer)
require.NoError(err)
require.NoError(writer.Err())
abiBytes := chain.MustMarshal(&abiFromFile)

abiHash := sha256.Sum256(writer.Bytes())
abiHash := sha256.Sum256(abiBytes)
expectedHashHex := strings.TrimSpace(string(mustReadFile(t, "testdata/abi.hash.hex")))
require.Equal(expectedHashHex, hex.EncodeToString(abiHash[:]))
}
Expand Down
8 changes: 7 additions & 1 deletion abi/codegen.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,17 @@ func GenerateGoStructs(abi ABI, packageName string) (string, error) {
}

for _, action := range abi.Actions {
sb.WriteString(fmt.Sprintf("func (%s) GetTypeID() uint8 {\n", action.Action))
sb.WriteString(fmt.Sprintf("func (%s) GetTypeID() uint8 {\n", action.Name))
sb.WriteString(fmt.Sprintf("\treturn %d\n", action.ID))
sb.WriteString("}\n\n")
}

for _, output := range abi.Outputs {
sb.WriteString(fmt.Sprintf("func (%s) GetTypeID() uint8 {\n", output.Name))
sb.WriteString(fmt.Sprintf("\treturn %d\n", output.ID))
sb.WriteString("}\n\n")
}

formatted, err := format.Source([]byte(sb.String()))
if err != nil {
return "", fmt.Errorf("failed to format generated code: %w", err)
Expand Down
8 changes: 0 additions & 8 deletions abi/codegen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
package abi

import (
"encoding/json"
"go/format"
"strings"
"testing"
Expand Down Expand Up @@ -38,10 +37,3 @@ func removeCommentLines(input []byte) []byte {
}
return []byte(strings.Join(result, "\n"))
}

func mustJSONParse[T any](t *testing.T, jsonStr string) T {
var parsed T
err := json.Unmarshal([]byte(jsonStr), &parsed)
require.NoError(t, err, jsonStr)
return parsed
}
28 changes: 22 additions & 6 deletions abi/mockabi_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,34 +63,50 @@ type Inner struct {
Field1 uint8 `serialize:"true" json:"field1"`
}

type ActionWithOutput struct {
Field1 uint8 `serialize:"true" json:"field1"`
}

type ActionOutput struct {
Field1 uint16 `serialize:"true" json:"field1"`
}

func (MockObjectSingleNumber) GetTypeID() uint8 {
return 1
return 0
}

func (MockActionTransfer) GetTypeID() uint8 {
return 2
return 1
}

func (MockObjectAllNumbers) GetTypeID() uint8 {
return 3
return 2
}

func (MockObjectStringAndBytes) GetTypeID() uint8 {
return 4
return 3
}

func (MockObjectArrays) GetTypeID() uint8 {
return 5
return 4
}

func (MockActionWithTransfer) GetTypeID() uint8 {
return 7
return 5
}

func (MockActionWithTransferArray) GetTypeID() uint8 {
return 6
}

func (Outer) GetTypeID() uint8 {
return 7
}

func (ActionWithOutput) GetTypeID() uint8 {
return 8
}

func (ActionOutput) GetTypeID() uint8 {
return 0
}
13 changes: 9 additions & 4 deletions abi/testdata/abi.abi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@
"actions": [
{
"id": 0,
"action": "ABI"
"name": "ABI"
}
],
"outputs": [],
"types": [
{
"name": "ABI",
"fields": [
{
"name": "actions",
"type": "[]Action"
"type": "[]TypedStruct"
},
{
"name": "outputs",
"type": "[]TypedStruct"
},
{
"name": "types",
Expand All @@ -20,14 +25,14 @@
]
},
{
"name": "Action",
"name": "TypedStruct",
"fields": [
{
"name": "id",
"type": "uint8"
},
{
"name": "action",
"name": "name",
"type": "string"
}
]
Expand Down
2 changes: 1 addition & 1 deletion abi/testdata/abi.hash.hex
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7ff1747a2f5f997a3a015934deac671469684c1d0567abb213c6cd5c2b564309
bffd5b2422e5c0fcdfff1b2c073efcac65ab0b5225461ca9a665638d41378e8e
Loading

0 comments on commit e17f286

Please sign in to comment.