Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix client checksum verification #1234

Merged
merged 2 commits into from
Mar 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions x/wasm/client/cli/gov_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import (
"strconv"
"strings"

"github.com/CosmWasm/wasmd/x/wasm/ioutils"

"github.com/docker/distribution/reference"

"github.com/cosmos/cosmos-sdk/client"
Expand Down Expand Up @@ -95,7 +97,7 @@ func ProposalStoreCodeCmd() *cobra.Command {
return cmd
}

func parseVerificationFlags(wasm []byte, flags *flag.FlagSet) (string, string, []byte, error) {
func parseVerificationFlags(gzippedWasm []byte, flags *flag.FlagSet) (string, string, []byte, error) {
source, err := flags.GetString(flagSource)
if err != nil {
return "", "", nil, fmt.Errorf("source: %s", err)
Expand Down Expand Up @@ -126,10 +128,14 @@ func parseVerificationFlags(wasm []byte, flags *flag.FlagSet) (string, string, [
if len(codeHash) == 0 {
return "", "", nil, fmt.Errorf("code hash is required")
}
// wasm is unzipped in parseStoreCodeArgs
// wasm is gzipped in parseStoreCodeArgs
// checksum generation will be decoupled here
// reference https://github.com/CosmWasm/wasmvm/issues/359
checksum := sha256.Sum256(wasm)
raw, err := ioutils.Uncompress(gzippedWasm, uint64(types.MaxWasmSize))
if err != nil {
return "", "", nil, fmt.Errorf("invalid zip: %w", err)
}
checksum := sha256.Sum256(raw)
if !bytes.Equal(checksum[:], codeHash) {
return "", "", nil, fmt.Errorf("code-hash mismatch: %X, checksum: %X", codeHash, checksum)
}
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/client/cli/gov_tx_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ func TestParseCodeInfoFlags(t *testing.T) {
correctSource := "https://github.com/CosmWasm/wasmd/blob/main/x/wasm/keeper/testdata/hackatom.wasm"
correctBuilderRef := "cosmwasm/workspace-optimizer:0.12.9"

wasmBin, err := os.ReadFile("../../keeper/testdata/hackatom.wasm")
wasmBin, err := os.ReadFile("../../keeper/testdata/hackatom.wasm.gzip")
require.NoError(t, err)

checksumStr := "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b"
Expand Down
1 change: 1 addition & 0 deletions x/wasm/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func StoreCodeCmd() *cobra.Command {
return cmd
}

// Prepares MsgStoreCode object from flags with gzipped wasm byte code field
func parseStoreCodeArgs(file string, sender sdk.AccAddress, flags *flag.FlagSet) (types.MsgStoreCode, error) {
wasm, err := os.ReadFile(file)
if err != nil {
Expand Down
65 changes: 65 additions & 0 deletions x/wasm/client/cli/tx_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
package cli

import (
"encoding/hex"
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/CosmWasm/wasmd/x/wasm/ioutils"
"github.com/CosmWasm/wasmd/x/wasm/types"
)

Expand Down Expand Up @@ -57,3 +60,65 @@ func TestParseAccessConfigFlags(t *testing.T) {
})
}
}

func TestParseVerificationFlags(t *testing.T) {
mySender := sdk.MustAccAddressFromBech32("cosmos1wyqh3n50ecatjg4vww5crmtd0nmyzusnwckw4at4gluc0m5m477q4arfek")

specs := map[string]struct {
srcPath string
args []string
expErr bool
expSource string
expBuilder string
expCodeHash string
}{
"gov store zipped": {
srcPath: "../../keeper/testdata/hackatom.wasm.gzip",
args: []string{
"--instantiate-everybody=true", "--code-hash=beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
},
expBuilder: "cosmwasm/workspace-optimizer:0.12.11",
expSource: "https://example.com",
expCodeHash: "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
},
"gov store raw": {
srcPath: "../../keeper/testdata/hackatom.wasm",
args: []string{
"--instantiate-everybody=true", "--code-hash=beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
},
expBuilder: "cosmwasm/workspace-optimizer:0.12.11",
expSource: "https://example.com",
expCodeHash: "beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
},
"gov store checksum mismatch": {
srcPath: "../../keeper/testdata/hackatom.wasm",
args: []string{
"--instantiate-everybody=true", "--code-hash=0000de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b",
"--code-source-url=https://example.com", "--builder=cosmwasm/workspace-optimizer:0.12.11",
},
expErr: true,
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
flagSet := ProposalStoreCodeCmd().Flags()
require.NoError(t, flagSet.Parse(spec.args))

gotMsg, err := parseStoreCodeArgs(spec.srcPath, mySender, flagSet)
require.NoError(t, err)
require.True(t, ioutils.IsGzip(gotMsg.WASMByteCode))

gotSource, gotBuilder, gotCodeHash, gotErr := parseVerificationFlags(gotMsg.WASMByteCode, flagSet)
if spec.expErr {
require.Error(t, gotErr)
return
}
require.NoError(t, gotErr)
assert.Equal(t, spec.expSource, gotSource)
assert.Equal(t, spec.expBuilder, gotBuilder)
assert.Equal(t, spec.expCodeHash, hex.EncodeToString(gotCodeHash))
})
}
}
17 changes: 14 additions & 3 deletions x/wasm/keeper/proposal_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,20 +27,31 @@ func TestStoreCodeProposal(t *testing.T) {
CodeUploadAccess: types.AllowNobody,
InstantiateDefaultPermission: types.AccessTypeNobody,
})
wasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
rawWasmCode, err := os.ReadFile("./testdata/hackatom.wasm")
require.NoError(t, err)
gzippedWasmCode, err := os.ReadFile("./testdata/hackatom.wasm.gzip")
require.NoError(t, err)
checksum, err := hex.DecodeString("beb3de5e9b93b52e514c74ce87ccddb594b9bcd33b7f1af1bb6da63fc883917b")
require.NoError(t, err)

specs := map[string]struct {
codeID int64
code []byte
unpinCode bool
}{
"upload with pinning (default)": {
unpinCode: false,
code: rawWasmCode,
},
"upload with code unpin": {
unpinCode: true,
code: rawWasmCode,
},
"upload with raw wasm code": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

code: rawWasmCode,
},
"upload with zipped wasm code": {
code: gzippedWasmCode,
},
}

Expand All @@ -51,7 +62,7 @@ func TestStoreCodeProposal(t *testing.T) {

src := types.StoreCodeProposalFixture(func(p *types.StoreCodeProposal) {
p.RunAs = myActorAddress
p.WASMByteCode = wasmCode
p.WASMByteCode = spec.code
p.UnpinCode = spec.unpinCode
p.CodeHash = checksum
})
Expand All @@ -73,7 +84,7 @@ func TestStoreCodeProposal(t *testing.T) {

storedCode, err := wasmKeeper.GetByteCode(ctx, 1)
require.NoError(t, err)
assert.Equal(t, wasmCode, storedCode)
assert.Equal(t, rawWasmCode, storedCode)
})
}
}
Expand Down