Skip to content

Commit

Permalink
Merge pull request #3440 from Agoric/agorictest-15-p1
Browse files Browse the repository at this point in the history
Determinism fixes for `agorictest-16`
  • Loading branch information
michaelfig authored Jul 1, 2021
2 parents c113d0f + 08deab3 commit b20830f
Show file tree
Hide file tree
Showing 9 changed files with 107 additions and 12 deletions.
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/mock v1.5.0 h1:jlYHihg//f7RRwuPfptm04yp4s7O6Kw8EZiVYIGcH0g=
github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
Expand Down
39 changes: 36 additions & 3 deletions golang/cosmos/x/vbank/vbank.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vbank
import (
"encoding/json"
"fmt"
"sort"

"github.com/Agoric/agoric-sdk/golang/cosmos/vm"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -35,10 +36,37 @@ type vbankSingleBalanceUpdate struct {
Amount string `json:"amount"`
}

// Make vbankManyBalanceUpdates sortable
type vbankManyBalanceUpdates []vbankSingleBalanceUpdate

var _ sort.Interface = vbankManyBalanceUpdates{}

func (vbu vbankManyBalanceUpdates) Len() int {
return len(vbu)
}

func (vbu vbankManyBalanceUpdates) Less(i int, j int) bool {
if vbu[i].Address < vbu[j].Address {
return true
} else if vbu[i].Address > vbu[j].Address {
return false
}
if vbu[i].Denom < vbu[j].Denom {
return true
} else if vbu[i].Denom > vbu[j].Denom {
return false
}
return vbu[i].Amount < vbu[j].Amount
}

func (vbu vbankManyBalanceUpdates) Swap(i int, j int) {
vbu[i], vbu[j] = vbu[j], vbu[i]
}

type vbankBalanceUpdate struct {
Nonce uint64 `json:"nonce"`
Type string `json:"type"`
Updated []vbankSingleBalanceUpdate `json:"updated"`
Nonce uint64 `json:"nonce"`
Type string `json:"type"`
Updated vbankManyBalanceUpdates `json:"updated"`
}

func marshalBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToBalance map[string]sdk.Coins) ([]byte, error) {
Expand All @@ -53,6 +81,9 @@ func marshalBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToBalance map[s
Nonce: nonce,
Updated: make([]vbankSingleBalanceUpdate, 0, nentries),
}

// Note that Golang randomises the order of iteration, so we have to sort
// below to be deterministic.
for address, coins := range addressToBalance {
for _, coin := range coins {
update := vbankSingleBalanceUpdate{
Expand All @@ -64,6 +95,8 @@ func marshalBalanceUpdate(ctx sdk.Context, keeper Keeper, addressToBalance map[s
}
}

// Ensure we have a deterministic order of updates.
sort.Sort(event.Updated)
return json.Marshal(&event)
}

Expand Down
30 changes: 23 additions & 7 deletions golang/cosmos/x/vbank/vbank_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ func newBalances(opts ...balancesOption) balances {
return bal
}

func validateBalanceUpdate(vbu vbankBalanceUpdate) error {
if vbu.Type != "VBANK_BALANCE_UPDATE" {
return fmt.Errorf("bad balance update type: %s", vbu.Type)
}
for i, u := range vbu.Updated {
if i > 0 && vbu.Updated.Less(i, i-1) {
return fmt.Errorf("unordered balance update %v is before %v", vbu.Updated[i-1], u)
}
}
return nil
}

// decodeBalances unmarshals a JSON-encoded vbankBalanceUpdate into normalized balances.
// A nil input returns a nil balances.
func decodeBalances(encoded []byte) (balances, uint64, error) {
Expand All @@ -78,10 +90,12 @@ func decodeBalances(encoded []byte) (balances, uint64, error) {
if err != nil {
return nil, 0, err
}
if balanceUpdate.Type != "VBANK_BALANCE_UPDATE" {
return nil, 0, fmt.Errorf("bad balance update type: %s", balanceUpdate.Type)
err = validateBalanceUpdate(balanceUpdate)
if err != nil {
return nil, 0, err
}
b := newBalances()
fmt.Printf("updated balances %v\n", balanceUpdate.Updated)
for _, u := range balanceUpdate.Updated {
account(u.Address, coin(u.Denom, u.Amount))(b)
}
Expand Down Expand Up @@ -277,8 +291,9 @@ func Test_Receive_Give(t *testing.T) {
want := newBalances(account(addr1, coin("urun", "1000")))
got, gotNonce, err := decodeBalances([]byte(ret))
if err != nil {
t.Errorf("decode balances error = %v", err)
} else if !reflect.DeepEqual(got, want) {
t.Fatalf("decode balances error = %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}
nonce := uint64(1)
Expand Down Expand Up @@ -418,8 +433,9 @@ func Test_Receive_Grab(t *testing.T) {
want := newBalances(account(addr1, coin("ubld", "1000")))
got, gotNonce, err := decodeBalances([]byte(ret))
if err != nil {
t.Errorf("decode balances error = %v", err)
} else if !reflect.DeepEqual(got, want) {
t.Fatalf("decode balances error = %v", err)
}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}
nonce := uint64(1)
Expand Down Expand Up @@ -495,7 +511,7 @@ func Test_EndBlock_Events(t *testing.T) {
}
gotMsg, gotNonce, err := decodeBalances([]byte(msgsSent[0]))
if err != nil {
t.Errorf("decode balances error = %v", err)
t.Fatalf("decode balances error = %v", err)
}

nonce := uint64(1)
Expand Down
2 changes: 1 addition & 1 deletion packages/SwingSet/src/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export function makeStartXSnap(bundles, { snapStore, env, spawn }) {
// console.log('startXSnap from', { snapshotHash });
return snapStore.load(snapshotHash, async snapshot => {
const xs = doXSnap({ snapshot, name, handleCommand, ...xsnapOpts });
await xs.evaluate('null'); // ensure that spawn is done
await xs.isReady();
return xs;
});
}
Expand Down
8 changes: 8 additions & 0 deletions packages/xsnap/src/replay.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,10 @@ export function recordXSnap(options, folderPath, { writeFileSync }) {
const it = xsnap({ ...options, handleCommand });

return freeze({
isReady: async () => {
nextFile('isReady');
return it.isReady();
},
/** @param { Uint8Array } msg */
issueCommand: async msg => {
nextFile('issueCommand').put(msg);
Expand Down Expand Up @@ -215,6 +219,10 @@ export async function replayXSnap(
}
const file = rd.file(step);
switch (kind) {
case 'isReady':
// eslint-disable-next-line no-await-in-loop
await it.isReady();
break;
case 'evaluate':
running = it.evaluate(file.getText());
break;
Expand Down
3 changes: 3 additions & 0 deletions packages/xsnap/src/xsnap.c
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,9 @@ ExitCode main(int argc, char* argv[])
char command = *nsbuf;
// fprintf(stderr, "command: len %d %c arg: %s\n", nslen, command, nsbuf + 1);
switch(command) {
case 'R': // isReady
fxWriteNetString(toParent, ".", "", 0);
break;
case '?':
case 'e':
xsBeginCrank(machine, gxCrankMeteringLimit);
Expand Down
13 changes: 13 additions & 0 deletions packages/xsnap/src/xsnap.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,18 @@ export function xsnap(options) {
return Promise.race([vatCancelled, result]);
}

/**
* @returns {Promise<void>}
*/
async function isReady() {
const result = baton.then(async () => {
await messagesToXsnap.next(encoder.encode(`R`));
await runToIdle();
});
baton = result.catch(() => {});
return Promise.race([vatCancelled, result]);
}

/**
* @param {Uint8Array} message
* @returns {Promise<RunResult<Uint8Array>>}
Expand Down Expand Up @@ -305,6 +317,7 @@ export function xsnap(options) {
return freeze({
issueCommand,
issueStringCommand,
isReady,
close,
terminate,
evaluate,
Expand Down
2 changes: 1 addition & 1 deletion packages/xsnap/test/test-snapstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ test('create SES worker, save, restore, resume', async t => {

const worker = await store.load(h, async snapshot => {
const xs = xsnap({ name: 'ses-resume', snapshot, os: osType(), spawn });
await xs.evaluate('0');
await xs.isReady();
return xs;
});
t.teardown(() => worker.close());
Expand Down
21 changes: 21 additions & 0 deletions packages/xsnap/test/test-xs-perf.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,27 @@ test('meter details', async t => {
t.is(meterType, 'xs-meter-8');
});

test('isReady does not compute / allocate', async t => {
const opts = options(io);
const vat1 = xsnap(opts);
t.teardown(() => vat1.terminate());
const vat2 = xsnap(opts);
t.teardown(() => vat2.terminate());

await vat1.evaluate('null');
const { meterUsage: m1 } = await vat1.evaluate('null');
t.log(m1);

await vat2.evaluate('null');
await vat2.isReady();
const { meterUsage: m2 } = await vat2.evaluate('null');

t.log(m2);

t.is(m1.compute, m2.compute);
t.is(m1.allocate, m2.allocate);
});

test('metering regex - REDOS', async t => {
const opts = options(io);
const vat = xsnap(opts);
Expand Down

0 comments on commit b20830f

Please sign in to comment.