Skip to content

Commit fd60061

Browse files
danforbesnootqdm12
authored
feat(lib/runtime): support Substrate WASM compression (#2213)
* Support Substrate Wasm compression https://github.com/paritytech/substrate/blob/master/primitives/maybe-compressed-blob/src/lib.rs * Apply suggestions from code review Co-authored-by: noot <[email protected]> * Review comments - slices cannot be const - create function & write tests - `go mod tidy` * Apply suggestions from code review Co-authored-by: Quentin McGaw <[email protected]> Co-authored-by: noot <[email protected]> Co-authored-by: Quentin McGaw <[email protected]>
1 parent 17e557d commit fd60061

File tree

3 files changed

+66
-1
lines changed

3 files changed

+66
-1
lines changed

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ require (
2727
github.com/ipfs/go-ds-badger2 v0.1.1
2828
github.com/ipfs/go-ipns v0.1.2 //indirect
2929
github.com/jpillora/ipfilter v1.2.3
30+
github.com/klauspost/compress v1.12.3
3031
github.com/libp2p/go-libp2p v0.15.1
3132
github.com/libp2p/go-libp2p-core v0.9.0
3233
github.com/libp2p/go-libp2p-discovery v0.5.1
@@ -84,7 +85,6 @@ require (
8485
github.com/jbenet/goprocess v0.1.4 // indirect
8586
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect
8687
github.com/jpillora/backoff v1.0.0 // indirect
87-
github.com/klauspost/compress v1.12.3 // indirect
8888
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
8989
github.com/koron/go-ssdp v0.0.2 // indirect
9090
github.com/leodido/go-urn v1.2.1 // indirect

lib/runtime/wasmer/instance.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package wasmer
55

66
import (
7+
"bytes"
78
"errors"
89
"fmt"
910
"sync"
@@ -18,6 +19,8 @@ import (
1819
"github.com/ChainSafe/gossamer/lib/crypto"
1920

2021
wasm "github.com/wasmerio/go-ext-wasm/wasmer"
22+
23+
"github.com/klauspost/compress/zstd"
2124
)
2225

2326
// Name represents the name of the interpreter
@@ -94,6 +97,12 @@ func NewInstance(code []byte, cfg *Config) (*Instance, error) {
9497
return nil, errors.New("code is empty")
9598
}
9699

100+
var err error
101+
code, err = decompressWasm(code)
102+
if err != nil {
103+
return nil, fmt.Errorf("cannot decompress WASM code: %w", err)
104+
}
105+
97106
logger.Patch(log.SetLevel(cfg.LogLvl), log.SetCallerFunc(true))
98107

99108
imports, err := cfg.Imports()
@@ -157,6 +166,22 @@ func NewInstance(code []byte, cfg *Config) (*Instance, error) {
157166
return inst, nil
158167
}
159168

169+
// decompressWasm decompresses a Wasm blob that may or may not be compressed with zstd
170+
// ref: https://github.com/paritytech/substrate/blob/master/primitives/maybe-compressed-blob/src/lib.rs
171+
func decompressWasm(code []byte) ([]byte, error) {
172+
compressionFlag := []byte{82, 188, 83, 118, 70, 219, 142, 5}
173+
if !bytes.HasPrefix(code, compressionFlag) {
174+
return code, nil
175+
}
176+
177+
decoder, err := zstd.NewReader(nil)
178+
if err != nil {
179+
return nil, fmt.Errorf("failed to create zstd decoder: %w", err)
180+
}
181+
182+
return decoder.DecodeAll(code[len(compressionFlag):], nil)
183+
}
184+
160185
// GetCodeHash returns the code of the instance
161186
func (in *Instance) GetCodeHash() common.Hash {
162187
return in.codeHash

lib/runtime/wasmer/instance_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"github.com/ChainSafe/gossamer/lib/runtime"
1212
"github.com/stretchr/testify/require"
13+
14+
"github.com/klauspost/compress/zstd"
1315
)
1416

1517
// test used for ensuring runtime exec calls can me made concurrently
@@ -63,3 +65,41 @@ func TestInstance_CheckRuntimeVersion(t *testing.T) {
6365
require.Equal(t, expected.ImplVersion(), version.ImplVersion())
6466
require.Equal(t, expected.TransactionVersion(), version.TransactionVersion())
6567
}
68+
69+
func TestDecompressWasm(t *testing.T) {
70+
encoder, err := zstd.NewWriter(nil)
71+
require.NoError(t, err)
72+
73+
cases := []struct {
74+
in []byte
75+
expected []byte
76+
msg string
77+
}{
78+
{
79+
[]byte{82, 188, 83, 118, 70, 219, 142},
80+
[]byte{82, 188, 83, 118, 70, 219, 142},
81+
"partial compression flag",
82+
},
83+
{
84+
[]byte{82, 188, 83, 118, 70, 219, 142, 6},
85+
[]byte{82, 188, 83, 118, 70, 219, 142, 6},
86+
"wrong compression flag",
87+
},
88+
{
89+
[]byte{82, 188, 83, 118, 70, 219, 142, 6, 221},
90+
[]byte{82, 188, 83, 118, 70, 219, 142, 6, 221},
91+
"wrong compression flag with data",
92+
},
93+
{
94+
append([]byte{82, 188, 83, 118, 70, 219, 142, 5}, encoder.EncodeAll([]byte("compressed"), nil)...),
95+
[]byte("compressed"),
96+
"compressed data",
97+
},
98+
}
99+
100+
for _, test := range cases {
101+
actual, err := decompressWasm(test.in)
102+
require.NoError(t, err)
103+
require.Equal(t, test.expected, actual)
104+
}
105+
}

0 commit comments

Comments
 (0)