-
Notifications
You must be signed in to change notification settings - Fork 107
/
runtime_message.go
132 lines (111 loc) · 3.58 KB
/
runtime_message.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package runtime
import (
"context"
"fmt"
beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/env"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis"
"github.com/oasisprotocol/oasis-core/go/oasis-test-runner/scenario"
"github.com/oasisprotocol/oasis-core/go/roothash/api/block"
"github.com/oasisprotocol/oasis-core/go/runtime/client/api"
staking "github.com/oasisprotocol/oasis-core/go/staking/api"
)
// RuntimeMessage is the runtime message scenario.
var RuntimeMessage scenario.Scenario = newRuntimeMessage()
type runtimeMessageImpl struct {
Scenario
}
func newRuntimeMessage() scenario.Scenario {
return &runtimeMessageImpl{
Scenario: *NewScenario("runtime-message", nil),
}
}
func (sc *runtimeMessageImpl) Clone() scenario.Scenario {
return &runtimeMessageImpl{
Scenario: *sc.Scenario.Clone().(*Scenario),
}
}
func (sc *runtimeMessageImpl) Fixture() (*oasis.NetworkFixture, error) {
f, err := sc.Scenario.Fixture()
if err != nil {
return nil, err
}
// Use mock epoch to ensure no rounds due to epoch transition. This way we
// test batch proposals when there are no transactions but message results.
f.Network.SetMockEpoch()
return f, nil
}
func (sc *runtimeMessageImpl) Run(ctx context.Context, _ *env.Env) error {
if err := sc.Net.Start(); err != nil {
return err
}
fixture, err := sc.Fixture()
if err != nil {
return err
}
var epoch beacon.EpochTime
if epoch, err = sc.initialEpochTransitions(ctx, fixture); err != nil {
return err
}
c := sc.Net.ClientController().RuntimeClient
blkCh, sub, err := c.WatchBlocks(ctx, KeyValueRuntimeID)
if err != nil {
return err
}
defer sub.Close()
// Submit a consensus transfer transaction. This should result in two runtime
// rounds:
// - in first round the consensus transfer transaction should be executed
// - in the second round there should be no transactions, the round should
// contain message results of the consensus transfer.
sc.Logger.Debug("submitting consensus_transfer runtime transaction")
var txMetaResponse *api.SubmitTxMetaResponse
if txMetaResponse, err = sc.submitConsensusXferTxMeta(ctx, staking.Transfer{}, 0); err != nil {
return err
}
if _, err = unpackRawTxResp(txMetaResponse.Output); err != nil {
return err
}
sc.Logger.Debug("transaction successful",
"epoch", epoch,
"round", txMetaResponse.Round,
)
latestRound := txMetaResponse.Round
// Round with the submitted consensus_transfer transaction.
blk, err := sc.WaitRuntimeBlock(blkCh, latestRound)
if err != nil {
return err
}
if ht := blk.Block.Header.HeaderType; ht != block.Normal {
return fmt.Errorf("expected normal round, got: %d", ht)
}
txs, err := c.GetTransactions(ctx, &api.GetTransactionsRequest{
RuntimeID: blk.Block.Header.Namespace,
Round: blk.Block.Header.Round,
})
if err != nil {
return err
}
if len(txs) != 1 {
return fmt.Errorf("expected 1 transaction at round: %d, got: %d", blk.Block.Header.Round, len(txs))
}
// Round with no transactions - triggered due to message results.
blk, err = sc.WaitRuntimeBlock(blkCh, blk.Block.Header.Round+1)
if err != nil {
return err
}
if ht := blk.Block.Header.HeaderType; ht != block.Normal {
return fmt.Errorf("expected normal round, got: %d", ht)
}
txs, err = c.GetTransactions(ctx, &api.GetTransactionsRequest{
RuntimeID: blk.Block.Header.Namespace,
Round: blk.Block.Header.Round,
})
if err != nil {
return err
}
if len(txs) != 0 {
return fmt.Errorf("expected 0 transactions at round: %d, got: %d", blk.Block.Header.Round, len(txs))
}
return nil
}