Skip to content

Commit

Permalink
Merge pull request #540 from CosmWasm/chipshort/migrate-version
Browse files Browse the repository at this point in the history
Contract Migrate Version
  • Loading branch information
chipshort authored Jun 26, 2024
2 parents 1c3fdc2 + 9ce2011 commit 69c8d72
Show file tree
Hide file tree
Showing 12 changed files with 938 additions and 316 deletions.
2 changes: 2 additions & 0 deletions ibc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@ func TestAnalyzeCode(t *testing.T) {
require.NoError(t, err)
require.False(t, report.HasIBCEntryPoints)
require.Equal(t, "", report.RequiredCapabilities)
require.Equal(t, uint64(42), *report.ContractMigrateVersion)

// Store IBC contract
wasm2, err := os.ReadFile(IBC_TEST_CONTRACT)
Expand All @@ -313,6 +314,7 @@ func TestAnalyzeCode(t *testing.T) {
require.NoError(t, err)
require.True(t, report2.HasIBCEntryPoints)
require.Equal(t, "iterator,stargate", report2.RequiredCapabilities)
require.Nil(t, report2.ContractMigrateVersion)
}

func TestIBCMsgGetChannel(t *testing.T) {
Expand Down
15 changes: 15 additions & 0 deletions internal/api/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,14 @@ typedef struct UnmanagedVector {
uintptr_t cap;
} UnmanagedVector;

/**
* A version of `Option<u64>` that can be used safely in FFI.
*/
typedef struct OptionalU64 {
bool is_some;
uint64_t value;
} OptionalU64;

/**
* The result type of the FFI function analyze_code.
*
Expand All @@ -217,6 +225,13 @@ typedef struct AnalysisReport {
* This is never None/nil.
*/
struct UnmanagedVector required_capabilities;
/**
* The migrate version of the contract.
* This is None if the contract does not have a migrate version and the `migrate` entrypoint
* needs to be called for every migration (if present).
* If it is `Some(version)`, it only needs to be called if the `version` increased.
*/
struct OptionalU64 contract_migrate_version;
} AnalysisReport;

typedef struct Metrics {
Expand Down
8 changes: 5 additions & 3 deletions internal/api/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,10 +161,12 @@ func AnalyzeCode(cache Cache, checksum []byte) (*types.AnalysisReport, error) {
}
requiredCapabilities := string(copyAndDestroyUnmanagedVector(report.required_capabilities))
entrypoints := string(copyAndDestroyUnmanagedVector(report.entrypoints))

res := types.AnalysisReport{
HasIBCEntryPoints: bool(report.has_ibc_entry_points),
RequiredCapabilities: requiredCapabilities,
Entrypoints: strings.Split(entrypoints, ","),
HasIBCEntryPoints: bool(report.has_ibc_entry_points),
RequiredCapabilities: requiredCapabilities,
Entrypoints: strings.Split(entrypoints, ","),
ContractMigrateVersion: optionalU64ToPtr(report.contract_migrate_version),
}
return &res, nil
}
Expand Down
34 changes: 17 additions & 17 deletions internal/api/lib_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(0), metrics.HitsMemoryCache)
require.Equal(t, uint32(1), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 2
msg2 := []byte(`{"verifier": "fred", "beneficiary": "susi"}`)
Expand All @@ -318,7 +318,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(1), metrics.HitsMemoryCache)
require.Equal(t, uint32(1), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Pin
err = Pin(cache, checksum)
Expand All @@ -331,8 +331,8 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(2), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 3
msg3 := []byte(`{"verifier": "fred", "beneficiary": "bert"}`)
Expand All @@ -347,8 +347,8 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(2), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Unpin
err = Unpin(cache, checksum)
Expand All @@ -363,7 +363,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint64(0), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.Equal(t, uint64(0), metrics.SizePinnedMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 4
msg4 := []byte(`{"verifier": "fred", "beneficiary": "jeff"}`)
Expand All @@ -379,7 +379,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint64(0), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.Equal(t, uint64(0), metrics.SizePinnedMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)
}

func TestInstantiate(t *testing.T) {
Expand All @@ -405,7 +405,7 @@ func TestInstantiate(t *testing.T) {
res, cost, err := Instantiate(cache, checksum, env, info, msg, &igasMeter, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0x5088ea), cost.UsedInternally)
assert.Equal(t, uint64(0x540eb6), cost.UsedInternally)

var result types.ContractResult
err = json.Unmarshal(res, &result)
Expand Down Expand Up @@ -436,7 +436,7 @@ func TestExecute(t *testing.T) {
diff := time.Since(start)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0x5088ea), cost.UsedInternally)
assert.Equal(t, uint64(0x540eb6), cost.UsedInternally)
t.Logf("Time (%d gas): %s\n", cost.UsedInternally, diff)

// execute with the same store
Expand All @@ -449,7 +449,7 @@ func TestExecute(t *testing.T) {
res, cost, err = Execute(cache, checksum, env, info, []byte(`{"release":{}}`), &igasMeter2, store, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
diff = time.Since(start)
require.NoError(t, err)
assert.Equal(t, uint64(0x8be9c6), cost.UsedInternally)
assert.Equal(t, uint64(0x975216), cost.UsedInternally)
t.Logf("Time (%d gas): %s\n", cost.UsedInternally, diff)

// make sure it read the balance properly and we got 250 atoms
Expand Down Expand Up @@ -557,7 +557,7 @@ func TestExecuteCpuLoop(t *testing.T) {
diff := time.Since(start)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0x365a42), cost.UsedInternally)
assert.Equal(t, uint64(0x3d997e), cost.UsedInternally)
t.Logf("Time (%d gas): %s\n", cost.UsedInternally, diff)

// execute a cpu loop
Expand Down Expand Up @@ -786,7 +786,7 @@ func TestMultipleInstances(t *testing.T) {
require.NoError(t, err)
requireOkResponse(t, res, 0)
// we now count wasm gas charges and db writes
assert.Equal(t, uint64(0x4ffce0), cost.UsedInternally)
assert.Equal(t, uint64(0x53541c), cost.UsedInternally)

// instance2 controlled by mary
gasMeter2 := NewMockGasMeter(TESTING_GAS_LIMIT)
Expand All @@ -797,14 +797,14 @@ func TestMultipleInstances(t *testing.T) {
res, cost, err = Instantiate(cache, checksum, env, info, msg, &igasMeter2, store2, api, &querier, TESTING_GAS_LIMIT, TESTING_PRINT_DEBUG)
require.NoError(t, err)
requireOkResponse(t, res, 0)
assert.Equal(t, uint64(0x504dbc), cost.UsedInternally)
assert.Equal(t, uint64(0x53bbb4), cost.UsedInternally)

// fail to execute store1 with mary
resp := exec(t, cache, checksum, "mary", store1, api, querier, 0x4a20c2)
resp := exec(t, cache, checksum, "mary", store1, api, querier, 0x503f70)
require.Equal(t, "Unauthorized", resp.Err)

// succeed to execute store1 with fred
resp = exec(t, cache, checksum, "fred", store1, api, querier, 0x8ba826)
resp = exec(t, cache, checksum, "fred", store1, api, querier, 0x970662)
require.Equal(t, "", resp.Err)
require.Equal(t, 1, len(resp.Ok.Messages))
attributes := resp.Ok.Attributes
Expand All @@ -813,7 +813,7 @@ func TestMultipleInstances(t *testing.T) {
require.Equal(t, "bob", attributes[1].Value)

// succeed to execute store2 with mary
resp = exec(t, cache, checksum, "mary", store2, api, querier, 0x8bc8f6)
resp = exec(t, cache, checksum, "mary", store2, api, querier, 0x972c3c)
require.Equal(t, "", resp.Err)
require.Equal(t, 1, len(resp.Ok.Messages))
attributes = resp.Ok.Attributes
Expand Down
7 changes: 7 additions & 0 deletions internal/api/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,13 @@ func copyAndDestroyUnmanagedVector(v C.UnmanagedVector) []byte {
return out
}

func optionalU64ToPtr(val C.OptionalU64) *uint64 {
if val.is_some {
return (*uint64)(&val.value)
}
return nil
}

// copyU8Slice copies the contents of an Option<&[u8]> that was allocated on the Rust side.
// Returns nil if and only if the source is None.
func copyU8Slice(view C.U8SliceView) []byte {
Expand Down
16 changes: 8 additions & 8 deletions lib_libwasmvm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(1), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
t.Log(metrics.SizeMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 2
msg2 := []byte(`{"verifier": "fred", "beneficiary": "susi"}`)
Expand All @@ -301,7 +301,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(1), metrics.HitsMemoryCache)
require.Equal(t, uint32(1), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Pin
err = vm.Pin(checksum)
Expand All @@ -314,8 +314,8 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(2), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 3
msg3 := []byte(`{"verifier": "fred", "beneficiary": "bert"}`)
Expand All @@ -333,8 +333,8 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint32(2), metrics.HitsFsCache)
require.Equal(t, uint64(1), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizePinnedMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Unpin
err = vm.Unpin(checksum)
Expand All @@ -349,7 +349,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint64(0), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.Equal(t, uint64(0), metrics.SizePinnedMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)

// Instantiate 4
msg4 := []byte(`{"verifier": "fred", "beneficiary": "jeff"}`)
Expand All @@ -368,7 +368,7 @@ func TestGetMetrics(t *testing.T) {
require.Equal(t, uint64(0), metrics.ElementsPinnedMemoryCache)
require.Equal(t, uint64(1), metrics.ElementsMemoryCache)
require.Equal(t, uint64(0), metrics.SizePinnedMemoryCache)
require.InEpsilon(t, 2832576, metrics.SizeMemoryCache, 0.25)
require.InEpsilon(t, 3700000, metrics.SizeMemoryCache, 0.25)
}

func TestLongPayloadDeserialization(t *testing.T) {
Expand Down
Loading

0 comments on commit 69c8d72

Please sign in to comment.