Uncompress gzip data in tx body

This commit is contained in:
Alex Peters
2020-01-09 14:04:47 +01:00
parent d12c434ab6
commit 88ed663832
5 changed files with 132 additions and 0 deletions

View 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)
}

View 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)
})
}
}

View File

@@ -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)

View File

@@ -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) {

Binary file not shown.