Uncompress gzip data in tx body
This commit is contained in:
38
x/wasm/internal/keeper/ioutil.go
Normal file
38
x/wasm/internal/keeper/ioutil.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// magic bytes to identify gzip.
|
||||
// See https://www.ietf.org/rfc/rfc1952.txt
|
||||
// and https://github.com/golang/go/blob/master/src/net/http/sniff.go#L186
|
||||
var gzipIdent = []byte("\x1F\x8B\x08")
|
||||
|
||||
// limit max bytes read to prevent gzip bombs
|
||||
const maxSize = 400 * 1024
|
||||
|
||||
// uncompress returns gzip uncompressed content or given src when not gzip.
|
||||
func uncompress(src []byte) ([]byte, error) {
|
||||
if len(src) < 3 {
|
||||
return src, nil
|
||||
}
|
||||
in := io.LimitReader(bytes.NewReader(src), maxSize)
|
||||
buf := make([]byte, 3)
|
||||
if _, err := io.ReadAtLeast(in, buf, 3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !bytes.Equal(gzipIdent, buf) {
|
||||
return src, nil
|
||||
}
|
||||
zr, err := gzip.NewReader(io.MultiReader(bytes.NewReader(buf), in))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
zr.Multistream(false)
|
||||
|
||||
return ioutil.ReadAll(zr)
|
||||
}
|
||||
63
x/wasm/internal/keeper/ioutil_test.go
Normal file
63
x/wasm/internal/keeper/ioutil_test.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestUncompress(t *testing.T) {
|
||||
wasmRaw, err := ioutil.ReadFile("./testdata/contract.wasm")
|
||||
require.NoError(t, err)
|
||||
|
||||
wasmGzipped, err := ioutil.ReadFile("./testdata/contract.wasm.gzip")
|
||||
require.NoError(t, err)
|
||||
|
||||
specs := map[string]struct {
|
||||
src []byte
|
||||
expError error
|
||||
expResult []byte
|
||||
}{
|
||||
"handle wasm uncompressed": {
|
||||
src: wasmRaw,
|
||||
expResult: wasmRaw,
|
||||
},
|
||||
"handle wasm compressed": {
|
||||
src: wasmGzipped,
|
||||
expResult: wasmRaw,
|
||||
},
|
||||
"handle nil slice": {
|
||||
src: nil,
|
||||
expResult: nil,
|
||||
},
|
||||
"handle short unidentified": {
|
||||
src: []byte{0x1, 0x2},
|
||||
expResult: []byte{0x1, 0x2},
|
||||
},
|
||||
"handle big slice": {
|
||||
src: []byte(strings.Repeat("a", maxSize+1)),
|
||||
expResult: []byte(strings.Repeat("a", maxSize+1)),
|
||||
},
|
||||
"handle gzip identifier only": {
|
||||
src: gzipIdent,
|
||||
expError: io.ErrUnexpectedEOF,
|
||||
},
|
||||
"handle broken gzip": {
|
||||
src: append(gzipIdent, byte(0x1)),
|
||||
expError: io.ErrUnexpectedEOF,
|
||||
},
|
||||
}
|
||||
for msg, spec := range specs {
|
||||
t.Run(msg, func(t *testing.T) {
|
||||
r, err := uncompress(spec.src)
|
||||
require.True(t, errors.Is(spec.expError, err), "exp %+v got %+v", spec.expError, err)
|
||||
assert.Equal(t, spec.expResult, r)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
@@ -58,6 +58,10 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, accountKeeper auth.Accou
|
||||
|
||||
// Create uploads and compiles a WASM contract, returning a short identifier for the contract
|
||||
func (k Keeper) Create(ctx sdk.Context, creator sdk.AccAddress, wasmCode []byte) (codeID uint64, sdkErr sdk.Error) {
|
||||
wasmCode, err := uncompress(wasmCode)
|
||||
if err != nil {
|
||||
return 0, types.ErrCreateFailed(err)
|
||||
}
|
||||
codeHash, err := k.wasmer.Create(wasmCode)
|
||||
if err != nil {
|
||||
return 0, types.ErrCreateFailed(err)
|
||||
|
||||
@@ -39,6 +39,33 @@ func TestCreate(t *testing.T) {
|
||||
contractID, err := keeper.Create(ctx, creator, wasmCode)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(1), contractID)
|
||||
// and verify content
|
||||
storedCode, err := keeper.GetByteCode(ctx, contractID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, wasmCode, storedCode)
|
||||
}
|
||||
|
||||
func TestCreateWithGzippedPayload(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "wasm")
|
||||
require.NoError(t, err)
|
||||
defer os.RemoveAll(tempDir)
|
||||
ctx, accKeeper, keeper := CreateTestInput(t, false, tempDir)
|
||||
|
||||
deposit := sdk.NewCoins(sdk.NewInt64Coin("denom", 100000))
|
||||
creator := createFakeFundedAccount(ctx, accKeeper, deposit)
|
||||
|
||||
wasmCode, err := ioutil.ReadFile("./testdata/contract.wasm.gzip")
|
||||
require.NoError(t, err)
|
||||
|
||||
contractID, err := keeper.Create(ctx, creator, wasmCode)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, uint64(1), contractID)
|
||||
// and verify content
|
||||
storedCode, err := keeper.GetByteCode(ctx, contractID)
|
||||
require.NoError(t, err)
|
||||
rawCode, err := ioutil.ReadFile("./testdata/contract.wasm")
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, rawCode, storedCode)
|
||||
}
|
||||
|
||||
func TestInstantiate(t *testing.T) {
|
||||
|
||||
BIN
x/wasm/internal/keeper/testdata/contract.wasm.gzip
vendored
Normal file
BIN
x/wasm/internal/keeper/testdata/contract.wasm.gzip
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user