Skip to content

Commit

Permalink
feat(lib/runtime): support Substrate WASM compression (#2213)
Browse files Browse the repository at this point in the history
* 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 <36753753+noot@users.noreply.github.com>

* Review comments

- slices cannot be const
- create function & write tests
- `go mod tidy`

* Apply suggestions from code review

Co-authored-by: Quentin McGaw <quentin.mcgaw@gmail.com>

Co-authored-by: noot <36753753+noot@users.noreply.github.com>
Co-authored-by: Quentin McGaw <quentin.mcgaw@gmail.com>
  • Loading branch information
3 people committed Jan 21, 2022
1 parent 17e557d commit fd60061
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 1 deletion.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/ipfs/go-ds-badger2 v0.1.1
github.com/ipfs/go-ipns v0.1.2 //indirect
github.com/jpillora/ipfilter v1.2.3
github.com/klauspost/compress v1.12.3
github.com/libp2p/go-libp2p v0.15.1
github.com/libp2p/go-libp2p-core v0.9.0
github.com/libp2p/go-libp2p-discovery v0.5.1
Expand Down Expand Up @@ -84,7 +85,6 @@ require (
github.com/jbenet/goprocess v0.1.4 // indirect
github.com/jcelliott/lumber v0.0.0-20160324203708-dd349441af25 // indirect
github.com/jpillora/backoff v1.0.0 // indirect
github.com/klauspost/compress v1.12.3 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/koron/go-ssdp v0.0.2 // indirect
github.com/leodido/go-urn v1.2.1 // indirect
Expand Down
25 changes: 25 additions & 0 deletions lib/runtime/wasmer/instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package wasmer

import (
"bytes"
"errors"
"fmt"
"sync"
Expand All @@ -18,6 +19,8 @@ import (
"github.com/ChainSafe/gossamer/lib/crypto"

wasm "github.com/wasmerio/go-ext-wasm/wasmer"

"github.com/klauspost/compress/zstd"
)

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

var err error
code, err = decompressWasm(code)
if err != nil {
return nil, fmt.Errorf("cannot decompress WASM code: %w", err)
}

logger.Patch(log.SetLevel(cfg.LogLvl), log.SetCallerFunc(true))

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

// decompressWasm decompresses a Wasm blob that may or may not be compressed with zstd
// ref: https://github.com/paritytech/substrate/blob/master/primitives/maybe-compressed-blob/src/lib.rs
func decompressWasm(code []byte) ([]byte, error) {
compressionFlag := []byte{82, 188, 83, 118, 70, 219, 142, 5}
if !bytes.HasPrefix(code, compressionFlag) {
return code, nil
}

decoder, err := zstd.NewReader(nil)
if err != nil {
return nil, fmt.Errorf("failed to create zstd decoder: %w", err)
}

return decoder.DecodeAll(code[len(compressionFlag):], nil)
}

// GetCodeHash returns the code of the instance
func (in *Instance) GetCodeHash() common.Hash {
return in.codeHash
Expand Down
40 changes: 40 additions & 0 deletions lib/runtime/wasmer/instance_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import (

"github.com/ChainSafe/gossamer/lib/runtime"
"github.com/stretchr/testify/require"

"github.com/klauspost/compress/zstd"
)

// test used for ensuring runtime exec calls can me made concurrently
Expand Down Expand Up @@ -63,3 +65,41 @@ func TestInstance_CheckRuntimeVersion(t *testing.T) {
require.Equal(t, expected.ImplVersion(), version.ImplVersion())
require.Equal(t, expected.TransactionVersion(), version.TransactionVersion())
}

func TestDecompressWasm(t *testing.T) {
encoder, err := zstd.NewWriter(nil)
require.NoError(t, err)

cases := []struct {
in []byte
expected []byte
msg string
}{
{
[]byte{82, 188, 83, 118, 70, 219, 142},
[]byte{82, 188, 83, 118, 70, 219, 142},
"partial compression flag",
},
{
[]byte{82, 188, 83, 118, 70, 219, 142, 6},
[]byte{82, 188, 83, 118, 70, 219, 142, 6},
"wrong compression flag",
},
{
[]byte{82, 188, 83, 118, 70, 219, 142, 6, 221},
[]byte{82, 188, 83, 118, 70, 219, 142, 6, 221},
"wrong compression flag with data",
},
{
append([]byte{82, 188, 83, 118, 70, 219, 142, 5}, encoder.EncodeAll([]byte("compressed"), nil)...),
[]byte("compressed"),
"compressed data",
},
}

for _, test := range cases {
actual, err := decompressWasm(test.in)
require.NoError(t, err)
require.Equal(t, test.expected, actual)
}
}

0 comments on commit fd60061

Please sign in to comment.