Skip to content

Commit 807e468

Browse files
committed
Enhance OpaqueCall and WrapperOpaque processing logic to improve payload handling and error management
1 parent b9c3c42 commit 807e468

9 files changed

Lines changed: 4973 additions & 9 deletions

File tree

extrinsic_kusama_opaque_test.go

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package scalecodec_test
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"os"
7+
"os/exec"
8+
"strconv"
9+
"testing"
10+
11+
scale "github.com/itering/scale.go"
12+
"github.com/itering/scale.go/source"
13+
"github.com/itering/scale.go/types"
14+
"github.com/itering/scale.go/types/scaleBytes"
15+
"github.com/itering/scale.go/utiles"
16+
"github.com/stretchr/testify/require"
17+
)
18+
19+
func TestKusamaOpaqueHistoricalBlocks(t *testing.T) {
20+
// Type registration is process-global. Keep historical chain definitions out
21+
// of unrelated network tests and exercise each runtime in a fresh process.
22+
specText := os.Getenv("SCALE_KUSAMA_OPAQUE_SPEC")
23+
if specText == "" {
24+
for _, spec := range []int{2015, 2029, 9070, 9260} {
25+
t.Run(strconv.Itoa(spec), func(t *testing.T) {
26+
cmd := exec.Command(os.Args[0], "-test.run=^TestKusamaOpaqueHistoricalBlocks$", "-test.v")
27+
cmd.Env = append(os.Environ(), fmt.Sprintf("SCALE_KUSAMA_OPAQUE_SPEC=%d", spec))
28+
out, err := cmd.CombinedOutput()
29+
require.NoError(t, err, "%s", out)
30+
})
31+
}
32+
return
33+
}
34+
spec, err := strconv.Atoi(specText)
35+
require.NoError(t, err)
36+
raw, err := os.ReadFile("testdata/kusama_opaque/types.json")
37+
require.NoError(t, err)
38+
types.RegCustomTypes(source.LoadTypeRegistry(raw))
39+
raw, err = os.ReadFile(fmt.Sprintf("testdata/kusama_opaque/metadata-%d.scale", spec))
40+
require.NoError(t, err)
41+
m := scale.MetadataDecoder{}
42+
m.Init(raw)
43+
m.Spec = spec
44+
require.NoError(t, m.Process())
45+
fixture, err := os.ReadFile("testdata/kusama_opaque/blocks.json")
46+
require.NoError(t, err)
47+
var blocks []struct {
48+
Height, Spec int
49+
MetadataVersion int `json:"metadata_version"`
50+
Extrinsics []struct {
51+
Raw string
52+
ExpectedCall string `json:"expected_call"`
53+
Params json.RawMessage
54+
}
55+
Events string
56+
EventCount int `json:"event_count"`
57+
Logs []string
58+
}
59+
require.NoError(t, json.Unmarshal(fixture, &blocks))
60+
require.Len(t, blocks, 16)
61+
count := 0
62+
for _, block := range blocks {
63+
if block.Spec != spec {
64+
continue
65+
}
66+
count++
67+
t.Run(strconv.Itoa(block.Height), func(t *testing.T) {
68+
require.Equal(t, block.MetadataVersion, m.Metadata.MetadataVersion)
69+
opt := types.ScaleDecoderOption{Metadata: &m.Metadata, Spec: spec}
70+
for i, x := range block.Extrinsics {
71+
t.Run(fmt.Sprintf("extrinsic_%d", i), func(t *testing.T) {
72+
input := utiles.HexToBytes(x.Raw)
73+
e := scale.ExtrinsicDecoder{}
74+
e.Init(scaleBytes.ScaleBytes{Data: input}, &opt)
75+
require.NotPanics(t, e.Process)
76+
require.Equal(t, len(input), e.Data.Offset)
77+
v := e.Value.(*scale.GenericExtrinsic)
78+
require.Equal(t, x.ExpectedCall, v.CallModule+"."+v.CallModuleFunction)
79+
got, err := json.Marshal(v.Params)
80+
require.NoError(t, err)
81+
var gotValue, wantValue interface{}
82+
require.NoError(t, json.Unmarshal(got, &gotValue))
83+
require.NoError(t, json.Unmarshal(x.Params, &wantValue))
84+
require.Equal(t, opaqueParamValues(wantValue), opaqueParamValues(gotValue))
85+
})
86+
}
87+
input := utiles.HexToBytes(block.Events)
88+
d := types.ScaleDecoder{}
89+
d.Init(scaleBytes.ScaleBytes{Data: input}, &opt)
90+
require.Equal(t, block.EventCount, d.ProcessAndUpdateData("Compact<u32>"))
91+
event := scale.EventRecord{Metadata: &m.Metadata}
92+
event.Init(d.Data, &opt)
93+
for i := 0; i < block.EventCount; i++ {
94+
require.NotPanics(t, func() { event.Process() })
95+
}
96+
require.Equal(t, len(input), event.Data.Offset)
97+
for _, log := range block.Logs {
98+
input := utiles.HexToBytes(log)
99+
d := types.ScaleDecoder{}
100+
d.Init(scaleBytes.ScaleBytes{Data: input}, nil)
101+
require.NotPanics(t, func() { d.ProcessAndUpdateData("LogDigest") })
102+
require.Equal(t, len(input), d.Data.Offset)
103+
}
104+
})
105+
}
106+
require.Equal(t, map[int]int{2015: 10, 2029: 2, 9070: 1, 9260: 3}[spec], count)
107+
}
108+
109+
// Expected values were captured by reading only the opaque argument as bytes.
110+
// Its diagnostic type label differs; compare parameter names and values while
111+
// retaining every byte (including the canonical empty opaque value "0x").
112+
func opaqueParamValues(v interface{}) interface{} {
113+
switch value := v.(type) {
114+
case []interface{}:
115+
for i, item := range value {
116+
value[i] = opaqueParamValues(item)
117+
}
118+
case map[string]interface{}:
119+
if value["type"] == "HexBytes" && value["value"] == "" {
120+
value["value"] = "0x"
121+
}
122+
delete(value, "type")
123+
delete(value, "type_name")
124+
for k, item := range value {
125+
value[k] = opaqueParamValues(item)
126+
}
127+
}
128+
return v
129+
}

0 commit comments

Comments
 (0)