diff --git a/.changelog/2880.feature.md b/.changelog/2880.feature.md new file mode 100644 index 00000000000..ea8ee75a650 --- /dev/null +++ b/.changelog/2880.feature.md @@ -0,0 +1 @@ +go/consensus/tendermint: Add support for state sync diff --git a/.changelog/2882.breaking.md b/.changelog/2882.breaking.md new file mode 100644 index 00000000000..689d46db74b --- /dev/null +++ b/.changelog/2882.breaking.md @@ -0,0 +1 @@ +go/consensus/tendermint: Bump Tendermint Core to 0.34 diff --git a/.changelog/2882.cfg.md b/.changelog/2882.cfg.md new file mode 100644 index 00000000000..dbfa480ba82 --- /dev/null +++ b/.changelog/2882.cfg.md @@ -0,0 +1,9 @@ +Remove explicit evidence-related consensus parameters + +The following evidence-related consensus parameters have been removed as they +are now derived based on the debonding period and other parameters: + +- `max_evidence_age_blocks` +- `max_evidence_age_time` + +Make sure to update the genesis file. diff --git a/go/common/grpc/grpc.go b/go/common/grpc/grpc.go index c59a911faca..707c0cd2dd8 100644 --- a/go/common/grpc/grpc.go +++ b/go/common/grpc/grpc.go @@ -612,7 +612,7 @@ func NewServer(config *ServerConfig) (*Server, error) { grpc.MaxRecvMsgSize(maxRecvMsgSize), grpc.MaxSendMsgSize(maxSendMsgSize), grpc.KeepaliveParams(serverKeepAliveParams), - grpc.CustomCodec(&CBORCodec{}), + grpc.CustomCodec(&CBORCodec{}), // nolint: staticcheck } if config.Identity != nil && config.Identity.GetTLSCertificate() != nil { tlsConfig := &tls.Config{ diff --git a/go/common/grpc/policy/policy_test.go b/go/common/grpc/policy/policy_test.go index 2cc004fdf66..3e5fcf00cdf 100644 --- a/go/common/grpc/policy/policy_test.go +++ b/go/common/grpc/policy/policy_test.go @@ -58,7 +58,7 @@ func TestAccessPolicy(t *testing.T) { Name: host, Port: port, Identity: &identity.Identity{}, - CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&cmnGrpc.CBORCodec{})}, + CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&cmnGrpc.CBORCodec{})}, // nolint: staticcheck } serverConfig.Identity.SetTLSCertificate(serverTLSCert) grpcServer, err := cmnGrpc.NewServer(serverConfig) diff --git a/go/common/grpc/proxy/proxy_test.go b/go/common/grpc/proxy/proxy_test.go index ee12bd66767..0e2cd9eb96f 100644 --- a/go/common/grpc/proxy/proxy_test.go +++ b/go/common/grpc/proxy/proxy_test.go @@ -60,7 +60,7 @@ func TestGRPCProxy(t *testing.T) { Name: host, Port: port, Identity: &identity.Identity{}, - CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&commonGrpc.CBORCodec{})}, + CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&commonGrpc.CBORCodec{})}, // nolint: staticcheck } serverConfig.Identity.SetTLSCertificate(serverTLSCert) grpcServer, err := commonGrpc.NewServer(serverConfig) diff --git a/go/common/grpc/wrapper_test.go b/go/common/grpc/wrapper_test.go index 92c73916f98..6722a6a7b30 100644 --- a/go/common/grpc/wrapper_test.go +++ b/go/common/grpc/wrapper_test.go @@ -216,7 +216,7 @@ func TestGrpcWrapper(t *testing.T) { serverConfig := &ServerConfig{ Name: host, Port: port, - CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&CBORCodec{})}, + CustomOptions: []grpc.ServerOption{grpc.CustomCodec(&CBORCodec{})}, // nolint: staticcheck InstallWrapper: true, } grpcServer, err := NewServer(serverConfig) diff --git a/go/consensus/genesis/genesis.go b/go/consensus/genesis/genesis.go index 73b6044c7a2..74e9b3a89ed 100644 --- a/go/consensus/genesis/genesis.go +++ b/go/consensus/genesis/genesis.go @@ -7,6 +7,7 @@ import ( "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags" ) // Genesis contains various consensus config flags that should be part of the genesis state. @@ -16,16 +17,15 @@ type Genesis struct { } // Parameters are the consensus parameters. -type Parameters struct { +type Parameters struct { // nolint: maligned TimeoutCommit time.Duration `json:"timeout_commit"` SkipTimeoutCommit bool `json:"skip_timeout_commit"` EmptyBlockInterval time.Duration `json:"empty_block_interval"` - MaxTxSize uint64 `json:"max_tx_size"` - MaxBlockSize uint64 `json:"max_block_size"` - MaxBlockGas transaction.Gas `json:"max_block_gas"` - MaxEvidenceAgeBlocks uint64 `json:"max_evidence_age_blocks"` - MaxEvidenceAgeTime time.Duration `json:"max_evidence_age_time"` + MaxTxSize uint64 `json:"max_tx_size"` + MaxBlockSize uint64 `json:"max_block_size"` + MaxBlockGas transaction.Gas `json:"max_block_gas"` + MaxEvidenceNum uint32 `json:"max_evidence_num"` // StateCheckpointInterval is the expected state checkpoint interval (in blocks). StateCheckpointInterval uint64 `json:"state_checkpoint_interval"` @@ -54,7 +54,7 @@ func (g *Genesis) SanityCheck() error { return fmt.Errorf("consensus: sanity check failed: timeout commit must be >= 1ms") } - if params.StateCheckpointInterval > 0 { + if params.StateCheckpointInterval > 0 && !flags.DebugDontBlameOasis() { if params.StateCheckpointInterval < 1000 { return fmt.Errorf("consensus: sanity check failed: state checkpoint interval must be >= 1000") } diff --git a/go/consensus/tendermint/abci/mux.go b/go/consensus/tendermint/abci/mux.go index 5239b3501a6..70ca2059b03 100644 --- a/go/consensus/tendermint/abci/mux.go +++ b/go/consensus/tendermint/abci/mux.go @@ -16,6 +16,7 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/cbor" "github.com/oasisprotocol/oasis-core/go/common/crypto/hash" @@ -30,6 +31,7 @@ import ( abciState "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/abci/state" "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/api" epochtime "github.com/oasisprotocol/oasis-core/go/epochtime/api" + "github.com/oasisprotocol/oasis-core/go/storage/mkvs/checkpoint" upgrade "github.com/oasisprotocol/oasis-core/go/upgrade/api" ) @@ -759,6 +761,13 @@ func (mux *abciMux) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock { // Update tags. resp.Events = ctx.GetEvents() + // Update version to what we are actually running. + resp.ConsensusParamUpdates = &types.ConsensusParams{ + Version: &tmproto.VersionParams{ + AppVersion: version.ConsensusProtocol.ToU64(), + }, + } + // Clear block context. mux.state.blockCtx = nil @@ -789,6 +798,223 @@ func (mux *abciMux) Commit() types.ResponseCommit { } } +func (mux *abciMux) ListSnapshots(req types.RequestListSnapshots) types.ResponseListSnapshots { + // Get a list of all current checkpoints. + cps, err := mux.state.storage.Checkpointer().GetCheckpoints(mux.state.ctx, &checkpoint.GetCheckpointsRequest{ + Version: 1, + }) + if err != nil { + mux.logger.Error("failed to get checkpoints", + "err", err, + ) + return types.ResponseListSnapshots{} + } + + var rsp types.ResponseListSnapshots + for _, cp := range cps { + cpHash := cp.EncodedHash() + + rsp.Snapshots = append(rsp.Snapshots, &types.Snapshot{ + Height: cp.Root.Version, + Format: uint32(cp.Version), + Chunks: uint32(len(cp.Chunks)), + Hash: cpHash[:], + Metadata: cbor.Marshal(cp), + }) + } + + return rsp +} + +func (mux *abciMux) OfferSnapshot(req types.RequestOfferSnapshot) types.ResponseOfferSnapshot { + if req.Snapshot == nil { + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + if req.Snapshot.Format != 1 { + mux.logger.Warn("received snapshot with unsupported version", + "version", req.Snapshot.Format, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT_FORMAT} + } + + // Decode checkpoint metadata hash and sanity check against the request. + var metadataHash hash.Hash + metadataHash.FromBytes(req.Snapshot.Metadata) + var h hash.Hash + if err := h.UnmarshalBinary(req.Snapshot.Hash); err != nil { + mux.logger.Warn("received snapshot with malformed hash", + "err", err, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + if !metadataHash.Equal(&h) { + mux.logger.Warn("received snapshot with mismatching hash", + "expected_hash", h, + "hash", metadataHash, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + + // Decode checkpoint metadata. + var cp checkpoint.Metadata + if err := cbor.Unmarshal(req.Snapshot.Metadata, &cp); err != nil { + mux.logger.Warn("received snapshot with malformed metadata", + "err", err, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + + // Number of chunks must match. + if int(req.Snapshot.Chunks) != len(cp.Chunks) { + mux.logger.Warn("received snapshot with mismatching number of chunks", + "expected_chunks", len(cp.Chunks), + "chunks", req.Snapshot.Chunks, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + // Root hash must match. + var appHash hash.Hash + if err := appHash.UnmarshalBinary(req.AppHash); err != nil { + // NOTE: This should never happen as it indicates a problem with Tendermint. + mux.logger.Error("received request with malformed hash", + "err", err, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_ABORT} + } + if !cp.Root.Hash.Equal(&appHash) { + mux.logger.Warn("received snapshot with mismatching root hash", + "expected_root", appHash, + "root", cp.Root.Hash, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_REJECT} + } + + // Snapshot seems correct (e.g., it is for the correct root), start the restoration process. + if err := mux.state.storage.Checkpointer().StartRestore(mux.state.ctx, &cp); err != nil { + mux.logger.Error("failed to start restore", + "err", err, + ) + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_ABORT} + } + + mux.logger.Info("started state restore process", + "root", cp.Root, + ) + + return types.ResponseOfferSnapshot{Result: types.ResponseOfferSnapshot_ACCEPT} +} + +func (mux *abciMux) LoadSnapshotChunk(req types.RequestLoadSnapshotChunk) types.ResponseLoadSnapshotChunk { + // Fetch the metadata for the specified checkpoint. + cps, err := mux.state.storage.Checkpointer().GetCheckpoints(mux.state.ctx, &checkpoint.GetCheckpointsRequest{ + Version: uint16(req.Format), + RootVersion: &req.Height, + }) + if err != nil { + mux.logger.Error("failed to get checkpoints", + "err", err, + ) + return types.ResponseLoadSnapshotChunk{} + } + if len(cps) != 1 { + mux.logger.Error("failed to get checkpoints", + "cps", len(cps), + ) + return types.ResponseLoadSnapshotChunk{} + } + + // Fetch the chunk itself. + chunk, err := cps[0].GetChunkMetadata(uint64(req.Chunk)) + if err != nil { + mux.logger.Error("failed to get chunk metadata", + "err", err, + ) + return types.ResponseLoadSnapshotChunk{} + } + var buf bytes.Buffer + if err := mux.state.storage.Checkpointer().GetCheckpointChunk(mux.state.ctx, chunk, &buf); err != nil { + mux.logger.Error("failed to get chunk", + "err", err, + ) + return types.ResponseLoadSnapshotChunk{} + } + + return types.ResponseLoadSnapshotChunk{Chunk: buf.Bytes()} +} + +func (mux *abciMux) ApplySnapshotChunk(req types.RequestApplySnapshotChunk) types.ResponseApplySnapshotChunk { + cp := mux.state.storage.Checkpointer().GetCurrentCheckpoint() + + mux.logger.Debug("attempting to restore a chunk", + "root", cp.Root, + "index", req.Index, + ) + + buf := bytes.NewBuffer(req.Chunk) + done, err := mux.state.storage.Checkpointer().RestoreChunk(mux.state.ctx, uint64(req.Index), buf) + switch { + case err == nil: + case errors.Is(err, checkpoint.ErrNoRestoreInProgress): + // This should never happen. + mux.logger.Error("ApplySnapshotChunk called without OfferSnapshot, aborting state sync") + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} + case errors.Is(err, checkpoint.ErrChunkAlreadyRestored): + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ACCEPT} + case errors.Is(err, checkpoint.ErrChunkCorrupted): + // Corrupted chunk, refetch. + mux.logger.Warn("received corrupted chunk", + "sender", req.Sender, + "index", req.Index, + "err", err, + ) + + return types.ResponseApplySnapshotChunk{ + RefetchChunks: []uint32{req.Index}, + // TODO: Consider banning the sender. + Result: types.ResponseApplySnapshotChunk_RETRY, + } + case errors.Is(err, checkpoint.ErrChunkProofVerificationFailed): + // Chunk was as specified in the manifest but did not match the reported root. In this case + // we need to abort processing the given snapshot. + mux.logger.Warn("chunk contains invalid proof, snapshot is bad", + "err", err, + ) + + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_REJECT_SNAPSHOT} + default: + // Unspecified error during restoration. + mux.logger.Error("error during chunk restoration, aborting state sync", + "err", err, + ) + + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} + } + + // Check if we are done with the restoration. In this case, finalize the root. + if done { + err = mux.state.storage.NodeDB().Finalize(mux.state.ctx, cp.Root.Version, []hash.Hash{cp.Root.Hash}) + if err != nil { + mux.logger.Error("failed to finalize restored root", + "err", err, + ) + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} + } + + if err = mux.state.doApplyStateSync(cp.Root); err != nil { + mux.logger.Error("failed to apply state sync root", + "err", err, + ) + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ABORT} + } + + mux.logger.Info("successfully synced state", + "root", cp.Root, + ) + } + + return types.ResponseApplySnapshotChunk{Result: types.ResponseApplySnapshotChunk_ACCEPT} +} + func (mux *abciMux) doCleanup() { mux.state.doCleanup() diff --git a/go/consensus/tendermint/abci/state.go b/go/consensus/tendermint/abci/state.go index 960592b4b9a..3bdf20b50a2 100644 --- a/go/consensus/tendermint/abci/state.go +++ b/go/consensus/tendermint/abci/state.go @@ -252,6 +252,24 @@ func (s *applicationState) doInitChain(now time.Time) error { return s.doCommitOrInitChainLocked(now) } +func (s *applicationState) doApplyStateSync(root storage.Root) error { + s.blockLock.Lock() + defer s.blockLock.Unlock() + + s.stateRoot = root + + s.deliverTxTree.Close() + s.deliverTxTree = mkvs.NewWithRoot(nil, s.storage.NodeDB(), root, mkvs.WithoutWriteLog()) + s.checkTxTree.Close() + s.checkTxTree = mkvs.NewWithRoot(nil, s.storage.NodeDB(), root, mkvs.WithoutWriteLog()) + + if err := s.doCommitOrInitChainLocked(time.Time{}); err != nil { + return err + } + + return nil +} + func (s *applicationState) doCommit(now time.Time) (uint64, error) { s.blockLock.Lock() defer s.blockLock.Unlock() diff --git a/go/consensus/tendermint/api/api.go b/go/consensus/tendermint/api/api.go index 7a5f8213d1f..8a9a175a1b8 100644 --- a/go/consensus/tendermint/api/api.go +++ b/go/consensus/tendermint/api/api.go @@ -7,10 +7,10 @@ import ( "strings" "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/libs/kv" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" tmquery "github.com/tendermint/tendermint/libs/pubsub/query" tmp2p "github.com/tendermint/tendermint/p2p" + tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" tmtypes "github.com/tendermint/tendermint/types" @@ -40,9 +40,10 @@ func PublicKeyToValidatorUpdate(id signature.PublicKey, power int64) types.Valid pk, _ := id.MarshalBinary() return types.ValidatorUpdate{ - PubKey: types.PubKey{ - Type: types.PubKeyEd25519, - Data: pk, + PubKey: tmcrypto.PublicKey{ + Sum: &tmcrypto.PublicKey_Ed25519{ + Ed25519: pk, + }, }, Power: power, } @@ -90,7 +91,7 @@ type EventBuilder struct { // Attribute appends a key/value pair to the event. func (bld *EventBuilder) Attribute(key, value []byte) *EventBuilder { - bld.ev.Attributes = append(bld.ev.Attributes, kv.Pair{ + bld.ev.Attributes = append(bld.ev.Attributes, types.EventAttribute{ Key: key, Value: value, }) diff --git a/go/consensus/tendermint/api/genesis.go b/go/consensus/tendermint/api/genesis.go index 1e52fd26a14..0ab7a586d4d 100644 --- a/go/consensus/tendermint/api/genesis.go +++ b/go/consensus/tendermint/api/genesis.go @@ -5,12 +5,15 @@ import ( "fmt" "time" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/node" "github.com/oasisprotocol/oasis-core/go/common/quantity" + "github.com/oasisprotocol/oasis-core/go/common/version" "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/crypto" genesis "github.com/oasisprotocol/oasis-core/go/genesis/api" + cmdFlags "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common/flags" registry "github.com/oasisprotocol/oasis-core/go/registry/api" scheduler "github.com/oasisprotocol/oasis-core/go/scheduler/api" staking "github.com/oasisprotocol/oasis-core/go/staking/api" @@ -69,22 +72,41 @@ func genesisToTendermint(d *genesis.Document) (*tmtypes.GenesisDoc, error) { maxBlockGas = -1 } + // Automatically compute evidence parameters based on debonding period. + debondingInterval := int64(d.Staking.Parameters.DebondingInterval) + if debondingInterval == 0 && cmdFlags.DebugDontBlameOasis() { + // Use a default of 1 epoch in case debonding is disabled and we are using debug mode. If + // not in debug mode, this will just cause startup to fail which is good. + debondingInterval = 1 + } + epochInterval := d.EpochTime.Parameters.Interval + if epochInterval == 0 && cmdFlags.DebugDontBlameOasis() && d.EpochTime.Parameters.DebugMockBackend { + // Use a default of 100 blocks in case epoch interval is unset and we are using debug mode. + epochInterval = 100 + } + + var evCfg tmproto.EvidenceParams + evCfg.MaxNum = d.Consensus.Parameters.MaxEvidenceNum + evCfg.MaxAgeNumBlocks = debondingInterval * epochInterval + evCfg.MaxAgeDuration = time.Duration(evCfg.MaxAgeNumBlocks) * (d.Consensus.Parameters.TimeoutCommit + 1*time.Second) + evCfg.ProofTrialPeriod = evCfg.MaxAgeNumBlocks / 2 + doc := tmtypes.GenesisDoc{ ChainID: d.ChainContext()[:tmtypes.MaxChainIDLen], GenesisTime: d.Time, - ConsensusParams: &tmtypes.ConsensusParams{ - Block: tmtypes.BlockParams{ + ConsensusParams: &tmproto.ConsensusParams{ + Block: tmproto.BlockParams{ MaxBytes: int64(d.Consensus.Parameters.MaxBlockSize), MaxGas: maxBlockGas, TimeIotaMs: 1000, }, - Evidence: tmtypes.EvidenceParams{ - MaxAgeNumBlocks: int64(d.Consensus.Parameters.MaxEvidenceAgeBlocks), - MaxAgeDuration: d.Consensus.Parameters.MaxEvidenceAgeTime, - }, - Validator: tmtypes.ValidatorParams{ + Evidence: evCfg, + Validator: tmproto.ValidatorParams{ PubKeyTypes: []string{tmtypes.ABCIPubKeyTypeEd25519}, }, + Version: tmproto.VersionParams{ + AppVersion: version.ConsensusProtocol.ToU64(), + }, }, AppState: b, } diff --git a/go/consensus/tendermint/apps/scheduler/genesis.go b/go/consensus/tendermint/apps/scheduler/genesis.go index ddc1c22edfc..90d94a534c7 100644 --- a/go/consensus/tendermint/apps/scheduler/genesis.go +++ b/go/consensus/tendermint/apps/scheduler/genesis.go @@ -37,20 +37,20 @@ func (app *schedulerApplication) InitChain(ctx *abciAPI.Context, req types.Reque staticValidators := make(map[signature.PublicKey]int64) for _, v := range req.Validators { tmPk := v.GetPubKey() + pk := tmPk.GetEd25519() - if t := tmPk.GetType(); t != types.PubKeyEd25519 { + if pk == nil { ctx.Logger().Error("invalid static validator public key type", - "public_key", hex.EncodeToString(tmPk.GetData()), - "type", t, + "type", v.GetPubKey(), ) - return fmt.Errorf("scheduler: invalid static validator public key type: '%v'", t) + return fmt.Errorf("scheduler: invalid static validator public key type: '%v'", v.GetPubKey()) } var id signature.PublicKey - if err = id.UnmarshalBinary(tmPk.GetData()); err != nil { + if err = id.UnmarshalBinary(pk); err != nil { ctx.Logger().Error("invalid static validator public key", "err", err, - "public_key", hex.EncodeToString(tmPk.GetData()), + "public_key", hex.EncodeToString(pk), ) return fmt.Errorf("scheduler: invalid static validator public key: %w", err) } @@ -103,20 +103,20 @@ func (app *schedulerApplication) InitChain(ctx *abciAPI.Context, req types.Reque currentValidators := make(map[signature.PublicKey]int64) for _, v := range req.Validators { tmPk := v.GetPubKey() + pk := tmPk.GetEd25519() - if t := tmPk.GetType(); t != types.PubKeyEd25519 { + if pk == nil { ctx.Logger().Error("invalid genesis validator public key type", - "public_key", hex.EncodeToString(tmPk.GetData()), - "type", t, + "type", v.GetPubKey(), ) - return fmt.Errorf("scheduler: invalid genesis validator public key type: '%v'", t) + return fmt.Errorf("scheduler: invalid genesis validator public key type: '%v'", v.GetPubKey()) } var id signature.PublicKey - if err = id.UnmarshalBinary(tmPk.GetData()); err != nil { + if err = id.UnmarshalBinary(pk); err != nil { ctx.Logger().Error("invalid genesis validator public key", "err", err, - "public_key", hex.EncodeToString(tmPk.GetData()), + "public_key", hex.EncodeToString(pk), ) return fmt.Errorf("scheduler: invalid genesis validator public key: %w", err) } diff --git a/go/consensus/tendermint/crypto/priv_val.go b/go/consensus/tendermint/crypto/priv_val.go index e1fb166d0d9..8bb01be89dd 100644 --- a/go/consensus/tendermint/crypto/priv_val.go +++ b/go/consensus/tendermint/crypto/priv_val.go @@ -207,6 +207,7 @@ import ( tmcrypto "github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/libs/tempfile" "github.com/tendermint/tendermint/privval" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" @@ -234,11 +235,11 @@ const ( stepPrecommit int8 = 3 ) -func voteToStep(vote *tmtypes.Vote) int8 { +func voteToStep(vote *tmproto.Vote) int8 { switch vote.Type { - case tmtypes.PrevoteType: + case tmproto.PrevoteType: return stepPrevote - case tmtypes.PrecommitType: + case tmproto.PrecommitType: return stepPrecommit default: panic("Unknown vote type") @@ -257,7 +258,7 @@ func (pv *privVal) GetPubKey() (tmcrypto.PubKey, error) { return PublicKeyToTendermint(&pv.PublicKey), nil } -func (pv *privVal) SignVote(chainID string, vote *tmtypes.Vote) error { +func (pv *privVal) SignVote(chainID string, vote *tmproto.Vote) error { height, round, step := vote.Height, vote.Round, voteToStep(vote) doubleSigned, err := pv.CheckHRS(height, round, step) @@ -265,7 +266,7 @@ func (pv *privVal) SignVote(chainID string, vote *tmtypes.Vote) error { return fmt.Errorf("tendermint/crypto: failed to check vote H/R/S: %w", err) } - signBytes := vote.SignBytes(chainID) + signBytes := tmtypes.VoteSignBytes(chainID, vote) if doubleSigned { if bytes.Equal(signBytes, pv.SignBytes) { vote.Signature = pv.Signature @@ -290,7 +291,7 @@ func (pv *privVal) SignVote(chainID string, vote *tmtypes.Vote) error { return nil } -func (pv *privVal) SignProposal(chainID string, proposal *tmtypes.Proposal) error { +func (pv *privVal) SignProposal(chainID string, proposal *tmproto.Proposal) error { height, round, step := proposal.Height, proposal.Round, stepPropose doubleSigned, err := pv.CheckHRS(height, round, step) @@ -298,7 +299,7 @@ func (pv *privVal) SignProposal(chainID string, proposal *tmtypes.Proposal) erro return fmt.Errorf("tendermint/crypto: failed to check proposal H/R/S: %w", err) } - signBytes := proposal.SignBytes(chainID) + signBytes := tmtypes.ProposalSignBytes(chainID, proposal) if doubleSigned { if bytes.Equal(signBytes, pv.SignBytes) { proposal.Signature = pv.Signature @@ -323,7 +324,7 @@ func (pv *privVal) SignProposal(chainID string, proposal *tmtypes.Proposal) erro return nil } -func (pv *privVal) update(height int64, round int, step int8, signBytes, sig []byte) error { +func (pv *privVal) update(height int64, round int32, step int8, signBytes, sig []byte) error { pv.Height = height pv.Round = round pv.Step = step diff --git a/go/consensus/tendermint/crypto/signature.go b/go/consensus/tendermint/crypto/signature.go index 0a942ba64ed..262e7ac50be 100644 --- a/go/consensus/tendermint/crypto/signature.go +++ b/go/consensus/tendermint/crypto/signature.go @@ -12,17 +12,17 @@ var tendermintSignatureContext = signature.NewContext("oasis-core/tendermint") // PublicKeyToTendermint converts a signature.PublicKey to the // tendermint equivalent. -func PublicKeyToTendermint(k *signature.PublicKey) tmed.PubKeyEd25519 { - var tk tmed.PubKeyEd25519 +func PublicKeyToTendermint(k *signature.PublicKey) tmed.PubKey { + tk := make(tmed.PubKey, tmed.PubKeySize) copy(tk[:], (*k)[:]) return tk } // PublicKeyFromTendermint converts a tendermint public key to a // signature.PublicKey. -func PublicKeyFromTendermint(tk *tmed.PubKeyEd25519) signature.PublicKey { +func PublicKeyFromTendermint(tk *tmed.PubKey) signature.PublicKey { var k signature.PublicKey - _ = k.UnmarshalBinary(tk[:]) + _ = k.UnmarshalBinary(tk.Bytes()) return k } @@ -56,6 +56,10 @@ func (s *tmSigner) Equals(other crypto.PrivKey) bool { return s.PubKey().Equals(other.PubKey()) } +func (s *tmSigner) Type() string { + return "ed25519" +} + func init() { tmed.EnableOasisDomainSeparation(string(tendermintSignatureContext)) } diff --git a/go/consensus/tendermint/crypto/signature_test.go b/go/consensus/tendermint/crypto/signature_test.go index a3bb9ba37e6..c9b6148a574 100644 --- a/go/consensus/tendermint/crypto/signature_test.go +++ b/go/consensus/tendermint/crypto/signature_test.go @@ -17,11 +17,11 @@ func TestSignatureConversions(t *testing.T) { tmSk := SignerToTendermint(signer) pk := signer.Public() - tmPk := tmSk.PubKey().(tmed.PubKeyEd25519) - require.Equal(t, pk[:], tmPk[:], "Private key: Public keys") + tmPk := tmSk.PubKey().(tmed.PubKey) + require.Equal(t, pk[:], tmPk.Bytes(), "Private key: Public keys") tmPk = PublicKeyToTendermint(&pk) - require.Equal(t, pk[:], tmPk[:], "Public key: ToTendermint") + require.Equal(t, pk[:], tmPk.Bytes(), "Public key: ToTendermint") pk2 := PublicKeyFromTendermint(&tmPk) require.Equal(t, pk[:], pk2[:], "Public key: FromTendermint") diff --git a/go/consensus/tendermint/db/badger/badger.go b/go/consensus/tendermint/db/badger/badger.go index dd62a259f4f..095ad39b2a1 100644 --- a/go/consensus/tendermint/db/badger/badger.go +++ b/go/consensus/tendermint/db/badger/badger.go @@ -381,7 +381,7 @@ func (it *badgerDBIterator) Error() error { return nil } -func (it *badgerDBIterator) Close() { +func (it *badgerDBIterator) Close() error { if it.iter != nil { it.iter.Close() it.tx.Discard() @@ -389,6 +389,7 @@ func (it *badgerDBIterator) Close() { it.tx = nil it.iter = nil } + return nil } type setDeleter interface { @@ -430,17 +431,19 @@ type badgerDBBatch struct { cmds []batchCmd } -func (ba *badgerDBBatch) Set(key, value []byte) { +func (ba *badgerDBBatch) Set(key, value []byte) error { ba.cmds = append(ba.cmds, &setCmd{ key: toDBKey(key), value: append([]byte{}, value...), }) + return nil } -func (ba *badgerDBBatch) Delete(key []byte) { +func (ba *badgerDBBatch) Delete(key []byte) error { ba.cmds = append(ba.cmds, &deleteCmd{ key: toDBKey(key), }) + return nil } func (ba *badgerDBBatch) Write() error { @@ -497,9 +500,10 @@ func (ba *badgerDBBatch) WriteSync() error { return err } -func (ba *badgerDBBatch) Close() { +func (ba *badgerDBBatch) Close() error { ba.db = nil ba.cmds = nil + return nil } func toDBKey(key []byte) []byte { diff --git a/go/consensus/tendermint/db/tests/tester.go b/go/consensus/tendermint/db/tests/tester.go index b1fe6cb7cf9..eb929ec93df 100644 --- a/go/consensus/tendermint/db/tests/tester.go +++ b/go/consensus/tendermint/db/tests/tester.go @@ -93,9 +93,12 @@ func testBatchOps(t *testing.T, db dbm.DB) { k1, k2 := []byte("key1"), []byte("key2") v1, v2 := []byte("value1"), []byte("value2") batch := db.NewBatch() - batch.Set(k1, v1) - batch.Set(k2, v2) - batch.Delete(toDeleteKey) + err = batch.Set(k1, v1) + require.NoError(err, "batch.Set(k1, v1)") + err = batch.Set(k2, v2) + require.NoError(err, "batch.Set(k2, v2)") + err = batch.Delete(toDeleteKey) + require.NoError(err, "batch.Delete(to-delete)") err = batch.Write() require.NoError(err, "batch.Write()") @@ -111,8 +114,10 @@ func testBatchOps(t *testing.T, db dbm.DB) { // Build and execute the clean-up batch. batch = db.NewBatch() - batch.Delete(k1) - batch.Delete(k2) + err = batch.Delete(k1) + require.NoError(err, "batch.Delete(k1)") + err = batch.Delete(k2) + require.NoError(err, "batch.Delete(k2)") err = batch.WriteSync() require.NoError(err, "batch.WriteSync()") exists, err = db.Has(k1) @@ -148,7 +153,8 @@ func testIterator(t *testing.T, db dbm.DB) { // Populate the database. batch := db.NewBatch() for _, ent := range entries { - batch.Set(ent.key, ent.value) + err := batch.Set(ent.key, ent.value) + require.NoError(err, "batch.Set(%s)", ent.key) } err := batch.Write() require.NoError(err, "batch.Write()") diff --git a/go/consensus/tendermint/full/full.go b/go/consensus/tendermint/full/full.go index 963075bab3e..3cd8071eb27 100644 --- a/go/consensus/tendermint/full/full.go +++ b/go/consensus/tendermint/full/full.go @@ -19,6 +19,7 @@ import ( tmabcitypes "github.com/tendermint/tendermint/abci/types" tmconfig "github.com/tendermint/tendermint/config" tmpubsub "github.com/tendermint/tendermint/libs/pubsub" + tmlight "github.com/tendermint/tendermint/light" tmmempool "github.com/tendermint/tendermint/mempool" tmnode "github.com/tendermint/tendermint/node" tmp2p "github.com/tendermint/tendermint/p2p" @@ -26,6 +27,7 @@ import ( tmcli "github.com/tendermint/tendermint/rpc/client/local" tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" tmstate "github.com/tendermint/tendermint/state" + tmstatesync "github.com/tendermint/tendermint/statesync" tmtypes "github.com/tendermint/tendermint/types" tmdb "github.com/tendermint/tm-db" @@ -55,6 +57,7 @@ import ( tmepochtime "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/epochtime" tmepochtimemock "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/epochtime_mock" tmkeymanager "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/keymanager" + "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/light" tmregistry "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/registry" tmroothash "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/roothash" tmscheduler "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/scheduler" @@ -122,6 +125,18 @@ const ( CfgSupplementarySanityEnabled = "consensus.tendermint.supplementarysanity.enabled" // CfgSupplementarySanityInterval configures the supplementary sanity check interval. CfgSupplementarySanityInterval = "consensus.tendermint.supplementarysanity.interval" + + // CfgConsensusStateSyncEnabled enabled consensus state sync. + CfgConsensusStateSyncEnabled = "consensus.tendermint.state_sync.enabled" + // CfgConsensusStateSyncConsensusNode specifies nodes exposing public consensus services which + // are used to sync a light client. + CfgConsensusStateSyncConsensusNode = "consensus.tendermint.state_sync.consensus_node" + // CfgConsensusStateSyncTrustPeriod is the light client trust period. + CfgConsensusStateSyncTrustPeriod = "consensus.tendermint.state_sync.trust_period" + // CfgConsensusStateSyncTrustHeight is the known trusted height for the light client. + CfgConsensusStateSyncTrustHeight = "consensus.tendermint.state_sync.trust_height" + // CfgConsensusStateSyncTrustHash is the known trusted block header hash for the light client. + CfgConsensusStateSyncTrustHash = "consensus.tendermint.state_sync.trust_hash" ) const ( @@ -1217,6 +1232,40 @@ func (t *fullService) lazyInit() error { return db, nil } + // Configure state sync if enabled. + var stateProvider tmstatesync.StateProvider + if viper.GetBool(CfgConsensusStateSyncEnabled) { + t.Logger.Info("state sync enabled") + + // Enable state sync in the configuration. + tenderConfig.StateSync.Enable = true + tenderConfig.StateSync.TrustHash = viper.GetString(CfgConsensusStateSyncTrustHash) + + // Create new state sync state provider. + cfg := light.ClientConfig{ + GenesisDocument: tmGenDoc, + TrustOptions: tmlight.TrustOptions{ + Period: viper.GetDuration(CfgConsensusStateSyncTrustPeriod), + Height: int64(viper.GetUint64(CfgConsensusStateSyncTrustHeight)), + Hash: tenderConfig.StateSync.TrustHashBytes(), + }, + } + for _, rawAddr := range viper.GetStringSlice(CfgConsensusStateSyncConsensusNode) { + var addr node.TLSAddress + if err = addr.UnmarshalText([]byte(rawAddr)); err != nil { + return fmt.Errorf("failed to parse state sync consensus node address (%s): %w", rawAddr, err) + } + + cfg.ConsensusNodes = append(cfg.ConsensusNodes, addr) + } + if stateProvider, err = newStateProvider(t.ctx, cfg); err != nil { + t.Logger.Error("failed to create state sync state provider", + "err", err, + ) + return fmt.Errorf("failed to create state sync state provider: %w", err) + } + } + // HACK: tmnode.NewNode() triggers block replay and or ABCI chain // initialization, instead of t.node.Start(). This is a problem // because at the time that lazyInit() is called, none of the ABCI @@ -1246,6 +1295,7 @@ func (t *fullService) lazyInit() error { wrapDbProvider, tmnode.DefaultMetricsProvider(tenderConfig.Instrumentation), tmcommon.NewLogAdapter(!viper.GetBool(tmcommon.CfgLogDebug)), + tmnode.StateProvider(stateProvider), ) if err != nil { return fmt.Errorf("tendermint: failed to create node: %w", err) @@ -1273,7 +1323,7 @@ func (t *fullService) syncWorker() { } }() - return t.node.ConsensusReactor().FastSync(), nil + return t.node.ConsensusReactor().WaitSync(), nil } for { @@ -1454,6 +1504,13 @@ func init() { Flags.Bool(CfgSupplementarySanityEnabled, false, "enable supplementary sanity checks (slows down consensus)") Flags.Uint64(CfgSupplementarySanityInterval, 10, "supplementary sanity check interval (in blocks)") + // State sync. + Flags.Bool(CfgConsensusStateSyncEnabled, false, "enable state sync") + Flags.StringSlice(CfgConsensusStateSyncConsensusNode, []string{}, "state sync: consensus node to use for syncing the light client") + Flags.Duration(CfgConsensusStateSyncTrustPeriod, 24*time.Hour, "state sync: light client trust period") + Flags.Uint64(CfgConsensusStateSyncTrustHeight, 0, "state sync: light client trusted height") + Flags.String(CfgConsensusStateSyncTrustHash, "", "state sync: light client trusted consensus header hash") + _ = Flags.MarkHidden(CfgDebugP2PAllowDuplicateIP) _ = Flags.MarkHidden(CfgDebugDisableCheckTx) _ = Flags.MarkHidden(CfgDebugUnsafeReplayRecoverCorruptedWAL) diff --git a/go/consensus/tendermint/full/light.go b/go/consensus/tendermint/full/light.go index 5651bba7619..6261545a9b5 100644 --- a/go/consensus/tendermint/full/light.go +++ b/go/consensus/tendermint/full/light.go @@ -4,8 +4,6 @@ import ( "context" "fmt" - tmamino "github.com/tendermint/go-amino" - tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" tmstate "github.com/tendermint/tendermint/state" "github.com/oasisprotocol/oasis-core/go/common/cbor" @@ -14,13 +12,6 @@ import ( "github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer" ) -// We must use Tendermint's amino codec as some Tendermint's types are not easily unmarshallable. -var aminoCodec = tmamino.NewCodec() - -func init() { - tmrpctypes.RegisterAmino(aminoCodec) -} - // Implements LightClientBackend. func (t *fullService) GetSignedHeader(ctx context.Context, height int64) (*consensusAPI.SignedHeader, error) { if err := t.ensureStarted(ctx); err != nil { @@ -36,9 +27,14 @@ func (t *fullService) GetSignedHeader(ctx context.Context, height int64) (*conse return nil, fmt.Errorf("tendermint: header is nil") } + meta, err := commit.SignedHeader.ToProto().Marshal() + if err != nil { + return nil, fmt.Errorf("tendermint: failed to marshal signed header: %w", err) + } + return &consensusAPI.SignedHeader{ Height: commit.Header.Height, - Meta: aminoCodec.MustMarshalBinaryBare(commit.SignedHeader), + Meta: meta, }, nil } @@ -54,9 +50,18 @@ func (t *fullService) GetValidatorSet(ctx context.Context, height int64) (*conse return nil, consensusAPI.ErrVersionNotFound } + protoVals, err := vals.ToProto() + if err != nil { + return nil, fmt.Errorf("tendermint: failed to convert validators: %w", err) + } + meta, err := protoVals.Marshal() + if err != nil { + return nil, fmt.Errorf("tendermint: failed to marshal validators: %w", err) + } + return &consensusAPI.ValidatorSet{ Height: height, - Meta: aminoCodec.MustMarshalBinaryBare(vals), + Meta: meta, }, nil } @@ -71,9 +76,14 @@ func (t *fullService) GetParameters(ctx context.Context, height int64) (*consens return nil, fmt.Errorf("%w: tendermint: consensus params query failed: %s", consensusAPI.ErrVersionNotFound, err.Error()) } + meta, err := params.ConsensusParams.Marshal() + if err != nil { + return nil, fmt.Errorf("tendermint: failed to marshal consensus params: %w", err) + } + return &consensusAPI.Parameters{ Height: params.BlockHeight, - Meta: aminoCodec.MustMarshalBinaryBare(params.ConsensusParams), + Meta: meta, }, nil } diff --git a/go/consensus/tendermint/full/statesync.go b/go/consensus/tendermint/full/statesync.go new file mode 100644 index 00000000000..9ad07a97b91 --- /dev/null +++ b/go/consensus/tendermint/full/statesync.go @@ -0,0 +1,123 @@ +package full + +import ( + "context" + "fmt" + "sync" + + tmstate "github.com/tendermint/tendermint/state" + tmstatesync "github.com/tendermint/tendermint/statesync" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/oasisprotocol/oasis-core/go/common/logging" + "github.com/oasisprotocol/oasis-core/go/common/version" + "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/light" +) + +type stateProvider struct { + sync.Mutex + + ctx context.Context + lc light.Client + genesisDocument *tmtypes.GenesisDoc + + logger *logging.Logger +} + +// Implements tmstatesync.StateProvider. +func (sp *stateProvider) AppHash(height uint64) ([]byte, error) { + sp.Lock() + defer sp.Unlock() + + // We have to fetch the next height, which contains the app hash for the previous height. + header, err := sp.lc.GetVerifiedSignedHeader(sp.ctx, int64(height+1)) + if err != nil { + return nil, err + } + return header.AppHash, nil +} + +// Implements tmstatesync.StateProvider. +func (sp *stateProvider) Commit(height uint64) (*tmtypes.Commit, error) { + sp.Lock() + defer sp.Unlock() + + header, err := sp.lc.GetVerifiedSignedHeader(sp.ctx, int64(height)) + if err != nil { + return nil, err + } + return header.Commit, nil +} + +// Implements tmstatesync.StateProvider. +func (sp *stateProvider) State(height uint64) (tmstate.State, error) { + sp.Lock() + defer sp.Unlock() + + state := tmstate.State{ + ChainID: sp.genesisDocument.ChainID, + Version: tmstate.InitStateVersion, + } + // XXX: This will fail in case an upgrade happened inbetween. + state.Version.Consensus.App = version.ConsensusProtocol.ToU64() + + // We need to verify up until h+2, to get the validator set. This also prefetches the headers + // for h and h+1 in the typical case where the trusted header is after the snapshot height. + _, err := sp.lc.GetVerifiedSignedHeader(sp.ctx, int64(height+2)) + if err != nil { + return tmstate.State{}, err + } + header, err := sp.lc.GetVerifiedSignedHeader(sp.ctx, int64(height)) + if err != nil { + return tmstate.State{}, err + } + nextHeader, err := sp.lc.GetVerifiedSignedHeader(sp.ctx, int64(height+1)) + if err != nil { + return tmstate.State{}, err + } + state.LastBlockHeight = header.Height + state.LastBlockTime = header.Time + state.LastBlockID = header.Commit.BlockID + state.AppHash = nextHeader.AppHash + state.LastResultsHash = nextHeader.LastResultsHash + + state.LastValidators, _, err = sp.lc.GetVerifiedValidatorSet(sp.ctx, int64(height)) + if err != nil { + return tmstate.State{}, err + } + state.Validators, _, err = sp.lc.GetVerifiedValidatorSet(sp.ctx, int64(height+1)) + if err != nil { + return tmstate.State{}, err + } + state.NextValidators, _, err = sp.lc.GetVerifiedValidatorSet(sp.ctx, int64(height+2)) + if err != nil { + return tmstate.State{}, err + } + state.LastHeightValidatorsChanged = int64(height) + + // Fetch consensus parameters with light client verification. + params, err := sp.lc.GetVerifiedParameters(sp.ctx, nextHeader.Height) + if err != nil { + return tmstate.State{}, fmt.Errorf("failed to fetch consensus parameters for height %d: %w", + nextHeader.Height, + err, + ) + } + state.ConsensusParams = *params + + return state, nil +} + +func newStateProvider(ctx context.Context, cfg light.ClientConfig) (tmstatesync.StateProvider, error) { + lc, err := light.NewClient(ctx, cfg) + if err != nil { + return nil, err + } + + return &stateProvider{ + ctx: ctx, + lc: lc, + genesisDocument: cfg.GenesisDocument, + logger: logging.GetLogger("consensus/tendermint/stateprovider"), + }, nil +} diff --git a/go/consensus/tendermint/light/client.go b/go/consensus/tendermint/light/client.go new file mode 100644 index 00000000000..b22119216cb --- /dev/null +++ b/go/consensus/tendermint/light/client.go @@ -0,0 +1,261 @@ +package light + +import ( + "bytes" + "context" + "errors" + "fmt" + "time" + + "github.com/spf13/viper" + "google.golang.org/grpc" + + tmlight "github.com/tendermint/tendermint/light" + tmlightprovider "github.com/tendermint/tendermint/light/provider" + tmlightdb "github.com/tendermint/tendermint/light/store/db" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + tmdb "github.com/tendermint/tm-db" + + "github.com/oasisprotocol/oasis-core/go/common/crypto/signature" + cmnGrpc "github.com/oasisprotocol/oasis-core/go/common/grpc" + "github.com/oasisprotocol/oasis-core/go/common/identity" + "github.com/oasisprotocol/oasis-core/go/common/node" + consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" + "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/common" + "github.com/oasisprotocol/oasis-core/go/storage/mkvs/syncer" +) + +// ClientConfig is the configuration for the light client. +type ClientConfig struct { + // GenesisDocument is the Tendermint genesis document. + GenesisDocument *tmtypes.GenesisDoc + + // ConsensusNodes is a list of nodes exposing the Oasis Core public consensus services that are + // used to fetch data required for syncing light clients. The first node is considered the + // primary and at least two nodes must be specified. + ConsensusNodes []node.TLSAddress + + // TrustOptions are Tendermint light client trust options. + TrustOptions tmlight.TrustOptions +} + +// lightClientProvider implements Tendermint's light client provider interface using the Oasis Core +// light client API. +type lightClientProvider struct { + ctx context.Context // XXX: Hack needed because tmlightprovider.Provider doesn't pass contexts. + + chainID string + client consensus.LightClientBackend +} + +// Implements tmlightprovider.Provider. +func (lp *lightClientProvider) ChainID() string { + return lp.chainID +} + +// Implements tmlightprovider.Provider. +func (lp *lightClientProvider) SignedHeader(height int64) (*tmtypes.SignedHeader, error) { + shdr, err := lp.client.GetSignedHeader(lp.ctx, height) + switch { + case err == nil: + case errors.Is(err, consensus.ErrVersionNotFound): + return nil, tmlightprovider.ErrSignedHeaderNotFound + default: + return nil, fmt.Errorf("failed to fetch signed header: %w", err) + } + + // Decode Tendermint-specific signed header. + var protoSigHdr tmproto.SignedHeader + if err = protoSigHdr.Unmarshal(shdr.Meta); err != nil { + return nil, fmt.Errorf("received malformed header: %w", err) + } + sh, err := tmtypes.SignedHeaderFromProto(&protoSigHdr) + if err != nil { + return nil, fmt.Errorf("received malformed header: %w", err) + } + + if lp.chainID != sh.ChainID { + return nil, fmt.Errorf("incorrect chain ID (expected: %s got: %s)", + lp.chainID, + sh.ChainID, + ) + } + + return sh, nil +} + +// Implements tmlightprovider.Provider. +func (lp *lightClientProvider) ValidatorSet(height int64) (*tmtypes.ValidatorSet, error) { + vs, err := lp.client.GetValidatorSet(lp.ctx, height) + switch { + case err == nil: + case errors.Is(err, consensus.ErrVersionNotFound): + return nil, tmlightprovider.ErrValidatorSetNotFound + default: + return nil, fmt.Errorf("failed to fetch validator set: %w", err) + } + + // Decode Tendermint-specific validator set. + var protoVals tmproto.ValidatorSet + if err = protoVals.Unmarshal(vs.Meta); err != nil { + return nil, fmt.Errorf("received malformed validator set: %w", err) + } + vals, err := tmtypes.ValidatorSetFromProto(&protoVals) + if err != nil { + return nil, fmt.Errorf("received malformed validator set: %w", err) + } + + return vals, nil +} + +// Implements tmlightprovider.Provider. +func (lp *lightClientProvider) ReportEvidence(ev tmtypes.Evidence) error { + // TODO: Implement SubmitEvidence. + return fmt.Errorf("not yet implemented") +} + +// newLightClientProvider creates a new provider for the Tendermint's light client. +// +// The provided chain ID must be the Tendermint chain ID. +func newLightClientProvider( + ctx context.Context, + chainID string, + address node.TLSAddress, +) (tmlightprovider.Provider, error) { + // Create TLS credentials. + opts := cmnGrpc.ClientOptions{ + CommonName: identity.CommonName, + ServerPubKeys: map[signature.PublicKey]bool{ + address.PubKey: true, + }, + } + creds, err := cmnGrpc.NewClientCreds(&opts) + if err != nil { + return nil, fmt.Errorf("failed to create TLS client credentials: %w", err) + } + + conn, err := cmnGrpc.Dial(address.Address.String(), grpc.WithTransportCredentials(creds)) + if err != nil { + return nil, fmt.Errorf("failed to dial public consensus service endpoint %s: %w", address, err) + } + + return &lightClientProvider{ + ctx: ctx, + chainID: chainID, + client: consensus.NewConsensusLightClient(conn), + }, nil +} + +type lightClient struct { + // tmc is the Tendermint light client used for verifying headers. + tmc *tmlight.Client +} + +// Implements consensus.LightClientBackend. +func (lc *lightClient) GetSignedHeader(ctx context.Context, height int64) (*consensus.SignedHeader, error) { + return lc.getPrimary().GetSignedHeader(ctx, height) +} + +// Implements consensus.LightClientBackend. +func (lc *lightClient) GetValidatorSet(ctx context.Context, height int64) (*consensus.ValidatorSet, error) { + return lc.getPrimary().GetValidatorSet(ctx, height) +} + +// Implements consensus.LightClientBackend. +func (lc *lightClient) GetParameters(ctx context.Context, height int64) (*consensus.Parameters, error) { + return lc.getPrimary().GetParameters(ctx, height) +} + +// Implements consensus.LightClientBackend. +func (lc *lightClient) State() syncer.ReadSyncer { + return lc.getPrimary().State() +} + +// Implements consensus.LightClientBackend. +func (lc *lightClient) SubmitTxNoWait(ctx context.Context, tx *transaction.SignedTransaction) error { + return lc.getPrimary().SubmitTxNoWait(ctx, tx) +} + +// Implements Client. +func (lc *lightClient) GetVerifiedSignedHeader(ctx context.Context, height int64) (*tmtypes.SignedHeader, error) { + return lc.tmc.VerifyHeaderAtHeight(height, time.Now()) +} + +func (lc *lightClient) GetVerifiedValidatorSet(ctx context.Context, height int64) (*tmtypes.ValidatorSet, int64, error) { + return lc.tmc.TrustedValidatorSet(height) +} + +// Implements Client. +func (lc *lightClient) GetVerifiedParameters(ctx context.Context, height int64) (*tmproto.ConsensusParams, error) { + p, err := lc.getPrimary().GetParameters(ctx, height) + if err != nil { + return nil, err + } + if p.Height <= 0 { + return nil, fmt.Errorf("malformed height in response: %d", p.Height) + } + + // Decode Tendermint-specific parameters. + var params tmproto.ConsensusParams + if err = params.Unmarshal(p.Meta); err != nil { + return nil, fmt.Errorf("malformed parameters: %w", err) + } + if err = tmtypes.ValidateConsensusParams(params); err != nil { + return nil, fmt.Errorf("malformed parameters: %w", err) + } + + // Fetch the header from the light client. + h, err := lc.tmc.VerifyHeaderAtHeight(p.Height, time.Now()) + if err != nil { + return nil, fmt.Errorf("failed to fetch header %d from light client: %w", p.Height, err) + } + + // Verify hash. + if localHash := tmtypes.HashConsensusParams(params); !bytes.Equal(localHash, h.ConsensusHash) { + return nil, fmt.Errorf("mismatched parameters hash (expected: %X got: %X)", + h.ConsensusHash, + localHash, + ) + } + + return ¶ms, nil +} + +func (lc *lightClient) getPrimary() consensus.LightClientBackend { + return lc.tmc.Primary().(*lightClientProvider).client +} + +// NewClient creates a new light client. +func NewClient(ctx context.Context, cfg ClientConfig) (Client, error) { + if numNodes := len(cfg.ConsensusNodes); numNodes < 2 { + return nil, fmt.Errorf("at least two consensus nodes must be provided (got %d)", numNodes) + } + + var providers []tmlightprovider.Provider + for _, address := range cfg.ConsensusNodes { + p, err := newLightClientProvider(ctx, cfg.GenesisDocument.ChainID, address) + if err != nil { + return nil, fmt.Errorf("failed to create light client provider: %w", err) + } + providers = append(providers, p) + } + + tmc, err := tmlight.NewClient( + cfg.GenesisDocument.ChainID, + cfg.TrustOptions, + providers[0], // Primary provider. + providers[1:], // Witnesses. + tmlightdb.New(tmdb.NewMemDB(), ""), // TODO: Make the database configurable. + tmlight.MaxRetryAttempts(5), // TODO: Make this configurable. + tmlight.Logger(common.NewLogAdapter(!viper.GetBool(common.CfgLogDebug))), + ) + if err != nil { + return nil, fmt.Errorf("failed to create light client: %w", err) + } + + return &lightClient{ + tmc: tmc, + }, nil +} diff --git a/go/consensus/tendermint/light/light.go b/go/consensus/tendermint/light/light.go new file mode 100644 index 00000000000..f31f381b2d7 --- /dev/null +++ b/go/consensus/tendermint/light/light.go @@ -0,0 +1,26 @@ +// Package light provides a light Tendermint consensus backend implementation. +package light + +import ( + "context" + + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmtypes "github.com/tendermint/tendermint/types" + + consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" +) + +// Client is a Tendermint consensus light client that talks with a remote oasis-node that is using +// the Tendermint consensus backend and verifies responses. +type Client interface { + consensus.LightClientBackend + + // GetVerifiedSignedHeader returns a verified signed header. + GetVerifiedSignedHeader(ctx context.Context, height int64) (*tmtypes.SignedHeader, error) + + // GetVerifiedValidatorSet returns a verified validator set. + GetVerifiedValidatorSet(ctx context.Context, height int64) (*tmtypes.ValidatorSet, int64, error) + + // GetVerifiedParameters returns verified consensus parameters. + GetVerifiedParameters(ctx context.Context, height int64) (*tmproto.ConsensusParams, error) +} diff --git a/go/consensus/tendermint/tests/evidence.go b/go/consensus/tendermint/tests/evidence.go index 0ccdc299edf..3608db1d8a6 100644 --- a/go/consensus/tendermint/tests/evidence.go +++ b/go/consensus/tendermint/tests/evidence.go @@ -8,6 +8,7 @@ import ( "time" "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/identity" @@ -45,23 +46,20 @@ func MakeDoubleSignEvidence(t *testing.T, ident *identity.Identity) consensus.Ev // different block IDs. blockID1 := tmtypes.BlockID{ Hash: []byte("blockhashblockhashblockhashbloc1"), - PartsHeader: tmtypes.PartSetHeader{ + PartSetHeader: tmtypes.PartSetHeader{ Total: 1000, Hash: []byte("partshashpartshashpartshashpart1"), }, } blockID2 := tmtypes.BlockID{ Hash: []byte("blockhashblockhashblockhashbloc1"), - PartsHeader: tmtypes.PartSetHeader{ + PartSetHeader: tmtypes.PartSetHeader{ Total: 1000, Hash: []byte("partshashpartshashpartshashpart2"), }, } now := time.Now() - pk, err := pv1.GetPubKey() - require.NoError(err, "GetPubKey") ev := &tmtypes.DuplicateVoteEvidence{ - PubKey: pk, // NOTE: ChainID must match the unit test genesis block. VoteA: makeVote(pv1, genesisTestHelpers.TestChainID, 0, 1, 2, 1, blockID1, now), VoteB: makeVote(pv2, genesisTestHelpers.TestChainID, 0, 1, 2, 1, blockID2, now), @@ -70,7 +68,7 @@ func MakeDoubleSignEvidence(t *testing.T, ident *identity.Identity) consensus.Ev } // makeVote copied from Tendermint test suite. -func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int, height int64, round, step int, blockID tmtypes.BlockID, ts time.Time) *tmtypes.Vote { +func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID tmtypes.BlockID, ts time.Time) *tmtypes.Vote { pk, err := val.GetPubKey() if err != nil { panic(err) @@ -81,13 +79,15 @@ func makeVote(val tmtypes.PrivValidator, chainID string, valIndex int, height in ValidatorIndex: valIndex, Height: height, Round: round, - Type: tmtypes.SignedMsgType(step), + Type: tmproto.SignedMsgType(step), BlockID: blockID, Timestamp: ts, } - err = val.SignVote(chainID, v) + vpb := v.ToProto() + err = val.SignVote(chainID, vpb) if err != nil { panic(err) } + v.Signature = vpb.Signature return v } diff --git a/go/consensus/tendermint/tests/genesis/genesis.go b/go/consensus/tendermint/tests/genesis/genesis.go index daa2be52057..fcb719156f3 100644 --- a/go/consensus/tendermint/tests/genesis/genesis.go +++ b/go/consensus/tendermint/tests/genesis/genesis.go @@ -5,9 +5,11 @@ import ( "math" "time" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/identity" + "github.com/oasisprotocol/oasis-core/go/common/version" consensus "github.com/oasisprotocol/oasis-core/go/consensus/genesis" tendermint "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/api" "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/crypto" @@ -88,6 +90,9 @@ func NewTestNodeGenesisProvider(identity *identity.Identity) (genesis.Provider, ConsensusParams: tmtypes.DefaultConsensusParams(), AppState: b, } + tmDoc.ConsensusParams.Version = tmproto.VersionParams{ + AppVersion: version.ConsensusProtocol.ToU64(), + } nodeID := identity.ConsensusSigner.Public() pk := crypto.PublicKeyToTendermint(&nodeID) diff --git a/go/extra/stats/cmd/stats.go b/go/extra/stats/cmd/stats.go index 86495dd73a3..1e1d0248741 100644 --- a/go/extra/stats/cmd/stats.go +++ b/go/extra/stats/cmd/stats.go @@ -11,8 +11,7 @@ import ( "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/spf13/viper" - tmamino "github.com/tendermint/go-amino" - tmrpctypes "github.com/tendermint/tendermint/rpc/core/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmtypes "github.com/tendermint/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/cbor" @@ -42,9 +41,6 @@ var ( } logger = logging.GetLogger("cmd/stats") - - // We must use Tendermint's amino codec as some Tendermint's types are not easily unmarshallable. - aminoCodec = tmamino.NewCodec() ) type nodeStats struct { @@ -306,8 +302,17 @@ func getStats(ctx context.Context, consensus consensusAPI.ClientBackend, registr ) os.Exit(1) } - var vals tmtypes.ValidatorSet - if err := aminoCodec.UnmarshalBinaryBare(vs.Meta, &vals); err != nil { + var protoVals tmproto.ValidatorSet + if err = protoVals.Unmarshal(vs.Meta); err != nil { + logger.Error("unmarshal validator set error", + "meta", vs.Meta, + "err", err, + "height", lastCommitHeight, + ) + os.Exit(1) + } + vals, err := tmtypes.ValidatorSetFromProto(&protoVals) + if err != nil { logger.Error("unmarshal validator set error", "meta", vs.Meta, "err", err, @@ -355,7 +360,7 @@ func getStats(ctx context.Context, consensus consensusAPI.ClientBackend, registr stats.nodeStatsOrExit(ctx, registry, lastCommitHeight, sig.ValidatorAddress.String()).signatures++ } - for i := 0; i < tmBlockMeta.LastCommit.Round; i++ { + for i := int32(0); i < tmBlockMeta.LastCommit.Round; i++ { // This round selected a validator to propose, but it didn't go through. logger.Debug("failed round", "height", lastCommitHeight, @@ -437,7 +442,3 @@ func RegisterStatsCmd(parentCmd *cobra.Command) { parentCmd.AddCommand(printStatsCmd) } - -func init() { - tmrpctypes.RegisterAmino(aminoCodec) -} diff --git a/go/genesis/genesis_test.go b/go/genesis/genesis_test.go index a6c162510a1..6a4189a833c 100644 --- a/go/genesis/genesis_test.go +++ b/go/genesis/genesis_test.go @@ -132,7 +132,7 @@ func TestGenesisChainContext(t *testing.T) { // on each run. stableDoc.Staking = staking.Genesis{} - require.Equal(t, "eb8815bbaf67dd9b08a3fe9810c5b71856d474d038188ca0adbaa4ef99b289e7", stableDoc.ChainContext()) + require.Equal(t, "0505b55140e999c7acd448aa74bfa52f90b6ffa7289840f7ff679b650fefc09d", stableDoc.ChainContext()) } func TestGenesisSanityCheck(t *testing.T) { diff --git a/go/go.mod b/go/go.mod index afcba62b0a9..70ec933a246 100644 --- a/go/go.mod +++ b/go/go.mod @@ -7,7 +7,7 @@ replace ( // https://github.com/spf13/cobra/issues/1091 github.com/gorilla/websocket => github.com/gorilla/websocket v1.4.2 - github.com/tendermint/tendermint => github.com/oasisprotocol/tendermint v0.33.6-oasis1 + github.com/tendermint/tendermint => github.com/oasisprotocol/tendermint v0.34.0-rc3-oasis1 golang.org/x/crypto/curve25519 => github.com/oasisprotocol/ed25519/extra/x25519 v0.0.0-20200528083105-55566edd6df0 golang.org/x/crypto/ed25519 => github.com/oasisprotocol/ed25519 v0.0.0-20200528083105-55566edd6df0 ) @@ -38,18 +38,17 @@ require ( github.com/oasisprotocol/deoxysii v0.0.0-20200527154044-851aec403956 github.com/oasisprotocol/ed25519 v0.0.0-20200528083105-55566edd6df0 github.com/opentracing/opentracing-go v1.2.0 - github.com/prometheus/client_golang v1.5.1 - github.com/prometheus/common v0.9.1 - github.com/prometheus/procfs v0.0.8 + github.com/prometheus/client_golang v1.7.1 + github.com/prometheus/common v0.10.0 + github.com/prometheus/procfs v0.1.3 github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect github.com/seccomp/libseccomp-golang v0.9.1 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 - github.com/spf13/viper v1.7.0 + github.com/spf13/viper v1.7.1 github.com/stretchr/testify v1.6.1 - github.com/tendermint/go-amino v0.15.0 github.com/tendermint/tendermint v0.33.6 - github.com/tendermint/tm-db v0.5.1 + github.com/tendermint/tm-db v0.6.0 github.com/thepudds/fzgo v0.2.2 github.com/uber/jaeger-client-go v2.25.0+incompatible github.com/uber/jaeger-lib v2.2.0+incompatible // indirect @@ -59,7 +58,8 @@ require ( golang.org/x/net v0.0.0-20200602114024-627f9648deb9 golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 // indirect google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a - google.golang.org/grpc v1.29.1 + google.golang.org/grpc v1.31.0 + google.golang.org/grpc/examples v0.0.0-20200625174016-7a808837ae92 // indirect google.golang.org/grpc/security/advancedtls v0.0.0-20200504170109-c8482678eb49 google.golang.org/protobuf v1.23.0 ) diff --git a/go/go.sum b/go/go.sum index a4abfa081e1..a253acc806f 100644 --- a/go/go.sum +++ b/go/go.sum @@ -221,7 +221,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= 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= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs= @@ -250,7 +249,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY= @@ -388,8 +386,8 @@ github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlT github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68= +github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -642,8 +640,8 @@ github.com/oasisprotocol/ed25519 v0.0.0-20200528083105-55566edd6df0 h1:qmiMZ6Zhk github.com/oasisprotocol/ed25519 v0.0.0-20200528083105-55566edd6df0/go.mod h1:IZbb50w3AB72BVobEF6qG93NNSrTw/V2QlboxqSu3Xw= github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661 h1:MB73kGMtuMGS+6VDoU/mitzff7Cu+aZo9ta5wabuxVA= github.com/oasisprotocol/safeopen v0.0.0-20200528085122-e01cfdfc7661/go.mod h1:SwBxaVibf6Sr2IZ6M3WnUue0yp8dPLAo1riQRNQ60+g= -github.com/oasisprotocol/tendermint v0.33.6-oasis1 h1:mqX0cHEFO26RsJXND7bPNCo7nUGQ4ENx+omkXBS9NVk= -github.com/oasisprotocol/tendermint v0.33.6-oasis1/go.mod h1:fMjshkHOy5okumxJQPvvz9PG3QD0F8dfiqWf1SBHsw4= +github.com/oasisprotocol/tendermint v0.34.0-rc3-oasis1 h1:J8sptLo0PLth+88EMFOTfsmhS7z1RcXAHoDnO0FDmew= +github.com/oasisprotocol/tendermint v0.34.0-rc3-oasis1/go.mod h1:pgZ5jfG7ZZ6p/9YLuJEG/k1OHIHfxPg7w4PU3VUbGiQ= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -675,6 +673,8 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5 h1:q2e307iGHPdTGp0hoxKjt1H5pDo6utceo3dQVK3I5XQ= +github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o= github.com/philhofer/fwd v1.0.0 h1:UbZqGr5Y38ApvM/V/jEljVxwocdweyH+vmYvRPBnbqQ= github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc= @@ -693,8 +693,8 @@ github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og= -github.com/prometheus/client_golang v1.5.1 h1:bdHYieyGlH+6OLEk2YQha8THib30KP0/yD0YH9m6xcA= -github.com/prometheus/client_golang v1.5.1/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU= +github.com/prometheus/client_golang v1.7.1 h1:NTGy1Ja9pByO+xAeH/qiWnLrKtr3hJPNjaVUwnjpdpA= +github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= @@ -710,8 +710,8 @@ github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y8 github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA= -github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U= -github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4= +github.com/prometheus/common v0.10.0 h1:RyRA7RzGXQZiW+tGMr7sxa85G1z0yOpM1qq5c8lNawc= +github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -719,6 +719,8 @@ github.com/prometheus/procfs v0.0.2 h1:6LJUbpNm42llc4HRCuvApCSWB/WfhuNo9K98Q9sNG github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8= github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A= +github.com/prometheus/procfs v0.1.3 h1:F0+tqvhOksq22sc6iCHF5WGlWjdwj92p0udFh1VFBS8= +github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= @@ -735,6 +737,8 @@ github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= +github.com/sasha-s/go-deadlock v0.2.0 h1:lMqc+fUb7RrFS3gQLtoQsJ7/6TV/pAIFvBsqX73DK8Y= +github.com/sasha-s/go-deadlock v0.2.0/go.mod h1:StQn567HiB1fF2yJ44N9au7wOhrPS3iZqiDbRupzT10= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= github.com/seccomp/libseccomp-golang v0.9.1 h1:NJjM5DNFOs0s3kYE1WUOr6G8V97sdt46rlXTMfXGWBo= github.com/seccomp/libseccomp-golang v0.9.1/go.mod h1:GbW5+tmTXfcxTToHLXlScSlAvWlF4P2Ca7zGrPiEpWo= @@ -774,9 +778,8 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= -github.com/spf13/viper v1.6.3/go.mod h1:jUMtyi0/lB5yZH/FjyGAoH7IMNrIhlBf6pXZmbMDvzw= -github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM= -github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= +github.com/spf13/viper v1.7.1 h1:pM5oEahlgWv/WnHXpgbKz7iLIxRf65tye2Ci+XFK5sk= +github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/src-d/envconfig v1.0.0/go.mod h1:Q9YQZ7BKITldTBnoxsE5gOeB5y66RyPXeue/R4aaNBc= github.com/steveyen/gtreap v0.1.0 h1:CjhzTa274PyJLJuMZwIzCO1PfC00oRa8d1Kc78bFXJM= github.com/steveyen/gtreap v0.1.0/go.mod h1:kl/5J7XbrOmlIbYIXdRHDDE5QxHqpk0cmkT7Z4dM9/Y= @@ -791,8 +794,6 @@ github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0 github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s= @@ -802,11 +803,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+ github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok= github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8= -github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= -github.com/tendermint/go-amino v0.15.0 h1:TC4e66P59W7ML9+bxio17CPKnxW3nKIRAYskntMAoRk= -github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= -github.com/tendermint/tm-db v0.5.1 h1:H9HDq8UEA7Eeg13kdYckkgwwkQLBnJGgX4PgLJRhieY= -github.com/tendermint/tm-db v0.5.1/go.mod h1:g92zWjHpCYlEvQXvy9M168Su8V1IBEeawpXVVBaK4f4= +github.com/tendermint/tm-db v0.6.0 h1:Us30k7H1UDcdqoSPhmP8ztAW/SWV6c6OfsfeCiboTC4= +github.com/tendermint/tm-db v0.6.0/go.mod h1:xj3AWJ08kBDlCHKijnhJ7mTcDMOikT1r8Poxy2pJn7Q= github.com/thepudds/fzgo v0.2.2 h1:bGofmgAGfTLpVgETkL9jvhg6azylvCF/kW6JPy5fkzQ= github.com/thepudds/fzgo v0.2.2/go.mod h1:ZgigL1toyKrar3rWdXz7Fuv7bUpKZ4BAYN49TpEFMCI= github.com/tinylib/msgp v1.1.0 h1:9fQd+ICuRIu/ue4vxJZu6/LzxN0HwMds2nq/0cFvxHU= @@ -849,6 +847,8 @@ go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.4 h1:hi1bXHMVrlQh6WwxAy+qZCV/SYIlqo+Ushwdpa4tAKg= go.etcd.io/bbolt v1.3.4/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= +go.etcd.io/bbolt v1.3.5 h1:XAzx9gjCb0Rxj7EoqcClPD1d5ZBxZJk0jbuoPHenBt0= +go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= @@ -944,8 +944,6 @@ golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7 h1:rTIdg5QFRR7XCaK4LCjBiPbx8j4DQRpdYMnGn/bJUEU= -golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -998,13 +996,12 @@ golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1 h1:ogLJMz+qpzav7lGMh10LMvAkM/fAoGlaiiHYiFYdm80= +golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6 h1:X9xIZ1YU8bLZA3l6gqDUHSFiD0GFI9S548h6C8nDtOY= golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1061,7 +1058,6 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1089,11 +1085,13 @@ google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8 google.golang.org/grpc v1.27.0 h1:rRYRFMVgRv6E0D70Skyfsr28tDXIuuPZyWGMPdMcnXg= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.28.1 h1:C1QC6KzgSiLyBabDi87BbjaGreoRgGUF5nOyvfrAZ1k= -google.golang.org/grpc v1.28.1/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60= -google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= +google.golang.org/grpc v1.30.0-dev.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.30.0 h1:M5a8xTlYTxwMn5ZFkwhRabsygDY5G8TYLyQDBxJNAxE= +google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.31.0 h1:T7P4R73V3SSDPhH7WW7ATbfViLtmamH0DKrP3f9AuDI= +google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc/examples v0.0.0-20200625174016-7a808837ae92 h1:zJsIxBOIY4bVTZS2uOJ35AcnayXX3alhJEsejLWezh0= +google.golang.org/grpc/examples v0.0.0-20200625174016-7a808837ae92/go.mod h1:wwLo5XaKQhinfnT+PqwJ17u2NXm7cllRQ4fKKyB22+w= google.golang.org/grpc/security/advancedtls v0.0.0-20200504170109-c8482678eb49 h1:0JUa0KgbivB+hPBKMrS/PEPhlzyH2gya70HZFd3Bi6E= google.golang.org/grpc/security/advancedtls v0.0.0-20200504170109-c8482678eb49/go.mod h1:MqvBVrZckRvDn3WrLNRHuHWrNGuZISOF4ohGDsL+tK4= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= diff --git a/go/oasis-net-runner/fixtures/default.go b/go/oasis-net-runner/fixtures/default.go index 98b64ceac8c..441b3a73032 100644 --- a/go/oasis-net-runner/fixtures/default.go +++ b/go/oasis-net-runner/fixtures/default.go @@ -9,6 +9,7 @@ import ( "github.com/oasisprotocol/oasis-core/go/common" "github.com/oasisprotocol/oasis-core/go/common/node" "github.com/oasisprotocol/oasis-core/go/common/sgx" + consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis" "github.com/oasisprotocol/oasis-core/go/oasis-test-runner/oasis" registry "github.com/oasisprotocol/oasis-core/go/registry/api" ) @@ -49,9 +50,13 @@ func newDefaultFixture() (*oasis.NetworkFixture, error) { Network: oasis.NetworkCfg{ NodeBinary: viper.GetString(cfgNodeBinary), RuntimeSGXLoaderBinary: viper.GetString(cfgRuntimeLoader), - ConsensusTimeoutCommit: 1 * time.Second, - EpochtimeMock: viper.GetBool(cfgEpochtimeMock), - HaltEpoch: viper.GetUint64(cfgHaltEpoch), + Consensus: consensusGenesis.Genesis{ + Parameters: consensusGenesis.Parameters{ + TimeoutCommit: 1 * time.Second, + }, + }, + EpochtimeMock: viper.GetBool(cfgEpochtimeMock), + HaltEpoch: viper.GetUint64(cfgHaltEpoch), IAS: oasis.IASCfg{ Mock: true, }, diff --git a/go/oasis-net-runner/fixtures/fixtures_test.go b/go/oasis-net-runner/fixtures/fixtures_test.go index 472c8a1f82c..0198a718620 100644 --- a/go/oasis-net-runner/fixtures/fixtures_test.go +++ b/go/oasis-net-runner/fixtures/fixtures_test.go @@ -5,6 +5,9 @@ import ( "testing" "github.com/stretchr/testify/require" + + "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis" ) func TestDefaultFixture(t *testing.T) { @@ -20,8 +23,10 @@ func TestDefaultFixture(t *testing.T) { func TestCustomFixture(t *testing.T) { f, _ := newDefaultFixture() f.Network.NodeBinary = "myNodeBinary" - f.Network.ConsensusBackend = "myConsensusBackend" - f.Network.ConsensusGasCostsTxByte = 123456789 + f.Network.Consensus.Backend = "myConsensusBackend" + f.Network.Consensus.Parameters.GasCosts = transaction.Costs{ + consensusGenesis.GasOpTxByte: 123456789, + } data, err := DumpFixture(f) require.Nil(t, err) diff --git a/go/oasis-node/cmd/debug/consim/mockchain.go b/go/oasis-node/cmd/debug/consim/mockchain.go index 0f114919898..c6e412c255b 100644 --- a/go/oasis-node/cmd/debug/consim/mockchain.go +++ b/go/oasis-node/cmd/debug/consim/mockchain.go @@ -10,6 +10,7 @@ import ( "time" "github.com/tendermint/tendermint/abci/types" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" "github.com/oasisprotocol/oasis-core/go/common/crypto/signature/signers/memory" "github.com/oasisprotocol/oasis-core/go/consensus/tendermint/abci" @@ -49,7 +50,7 @@ func (m *mockChain) beginBlock() { m.mux.BeginBlock(types.RequestBeginBlock{ Hash: m.hash, - Header: types.Header{ + Header: tmproto.Header{ ChainID: m.tmChainID, Height: m.height, Time: m.now, diff --git a/go/oasis-node/cmd/genesis/genesis.go b/go/oasis-node/cmd/genesis/genesis.go index e52446e9fbb..92c0cc4ec20 100644 --- a/go/oasis-node/cmd/genesis/genesis.go +++ b/go/oasis-node/cmd/genesis/genesis.go @@ -86,11 +86,10 @@ const ( cfgConsensusMaxTxSizeBytes = "consensus.tendermint.max_tx_size" cfgConsensusMaxBlockSizeBytes = "consensus.tendermint.max_block_size" cfgConsensusMaxBlockGas = "consensus.tendermint.max_block_gas" - cfgConsensusMaxEvidenceAgeBlocks = "consensus.tendermint.max_evidence_age_blocks" - cfgConsensusMaxEvidenceAgeTime = "consensus.tendermint.max_evidence_age_time" - cfgConsensusStateCheckpointInterval = "consensus.state_checkpoint.interval" - cfgConsensusStateCheckpointNumKept = "consensus.state_checkpoint.num_kept" - cfgConsensusStateCheckpointChunkSize = "consensus.state_checkpoint.chunk_size" + cfgConsensusMaxEvidenceNum = "consensus.tendermint.max_evidence_num" + CfgConsensusStateCheckpointInterval = "consensus.state_checkpoint.interval" + CfgConsensusStateCheckpointNumKept = "consensus.state_checkpoint.num_kept" + CfgConsensusStateCheckpointChunkSize = "consensus.state_checkpoint.chunk_size" CfgConsensusGasCostsTxByte = "consensus.gas_costs.tx_byte" cfgConsensusBlacklistPublicKey = "consensus.blacklist_public_key" @@ -241,11 +240,10 @@ func doInitGenesis(cmd *cobra.Command, args []string) { MaxTxSize: uint64(viper.GetSizeInBytes(cfgConsensusMaxTxSizeBytes)), MaxBlockSize: uint64(viper.GetSizeInBytes(cfgConsensusMaxBlockSizeBytes)), MaxBlockGas: transaction.Gas(viper.GetUint64(cfgConsensusMaxBlockGas)), - MaxEvidenceAgeBlocks: viper.GetUint64(cfgConsensusMaxEvidenceAgeBlocks), - MaxEvidenceAgeTime: viper.GetDuration(cfgConsensusMaxEvidenceAgeTime), - StateCheckpointInterval: viper.GetUint64(cfgConsensusStateCheckpointInterval), - StateCheckpointNumKept: viper.GetUint64(cfgConsensusStateCheckpointNumKept), - StateCheckpointChunkSize: uint64(viper.GetSizeInBytes(cfgConsensusStateCheckpointChunkSize)), + MaxEvidenceNum: viper.GetUint32(cfgConsensusMaxEvidenceNum), + StateCheckpointInterval: viper.GetUint64(CfgConsensusStateCheckpointInterval), + StateCheckpointNumKept: viper.GetUint64(CfgConsensusStateCheckpointNumKept), + StateCheckpointChunkSize: uint64(viper.GetSizeInBytes(CfgConsensusStateCheckpointChunkSize)), GasCosts: transaction.Costs{ consensusGenesis.GasOpTxByte: transaction.Gas(viper.GetUint64(CfgConsensusGasCostsTxByte)), }, @@ -696,11 +694,10 @@ func init() { initGenesisFlags.String(cfgConsensusMaxTxSizeBytes, "32kb", "tendermint maximum transaction size (in bytes)") initGenesisFlags.String(cfgConsensusMaxBlockSizeBytes, "21mb", "tendermint maximum block size (in bytes)") initGenesisFlags.Uint64(cfgConsensusMaxBlockGas, 0, "tendermint max gas used per block") - initGenesisFlags.Uint64(cfgConsensusMaxEvidenceAgeBlocks, 100000, "tendermint max evidence age (in blocks)") - initGenesisFlags.Duration(cfgConsensusMaxEvidenceAgeTime, 48*time.Hour, "tendermint max evidence age (in time)") - initGenesisFlags.Uint64(cfgConsensusStateCheckpointInterval, 10000, "consensus state checkpoint interval (in blocks)") - initGenesisFlags.Uint64(cfgConsensusStateCheckpointNumKept, 2, "number of kept consensus state checkpoints") - initGenesisFlags.String(cfgConsensusStateCheckpointChunkSize, "8mb", "consensus state checkpoint chunk size (in bytes)") + initGenesisFlags.Uint32(cfgConsensusMaxEvidenceNum, 50, "tendermint max evidence num") + initGenesisFlags.Uint64(CfgConsensusStateCheckpointInterval, 10000, "consensus state checkpoint interval (in blocks)") + initGenesisFlags.Uint64(CfgConsensusStateCheckpointNumKept, 2, "number of kept consensus state checkpoints") + initGenesisFlags.String(CfgConsensusStateCheckpointChunkSize, "8mb", "consensus state checkpoint chunk size (in bytes)") initGenesisFlags.Uint64(CfgConsensusGasCostsTxByte, 1, "consensus gas costs: each transaction byte") initGenesisFlags.StringSlice(cfgConsensusBlacklistPublicKey, nil, "blacklist public key") diff --git a/go/oasis-test-runner/oasis/args.go b/go/oasis-test-runner/oasis/args.go index 29ebc3ed469..aea4b7f9d6d 100644 --- a/go/oasis-test-runner/oasis/args.go +++ b/go/oasis-test-runner/oasis/args.go @@ -176,6 +176,22 @@ func (args *argBuilder) tendermintDebugAllowDuplicateIP() *argBuilder { return args } +func (args *argBuilder) tendermintStateSync( + consensusNodes []string, + trustHeight uint64, + trustHash string, +) *argBuilder { + args.vec = append(args.vec, + "--"+tendermintFull.CfgConsensusStateSyncEnabled, + "--"+tendermintFull.CfgConsensusStateSyncTrustHeight, strconv.FormatUint(trustHeight, 10), + "--"+tendermintFull.CfgConsensusStateSyncTrustHash, trustHash, + ) + for _, address := range consensusNodes { + args.vec = append(args.vec, "--"+tendermintFull.CfgConsensusStateSyncConsensusNode, address) + } + return args +} + func (args *argBuilder) storageBackend(backend string) *argBuilder { args.vec = append(args.vec, []string{ "--" + storage.CfgBackend, backend, diff --git a/go/oasis-test-runner/oasis/oasis.go b/go/oasis-test-runner/oasis/oasis.go index 65728174099..1e55ac0d034 100644 --- a/go/oasis-test-runner/oasis/oasis.go +++ b/go/oasis-test-runner/oasis/oasis.go @@ -25,6 +25,8 @@ import ( "github.com/oasisprotocol/oasis-core/go/common/identity" "github.com/oasisprotocol/oasis-core/go/common/logging" "github.com/oasisprotocol/oasis-core/go/common/node" + "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis" genesisFile "github.com/oasisprotocol/oasis-core/go/genesis/file" genesisTestHelpers "github.com/oasisprotocol/oasis-core/go/genesis/tests" "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common" @@ -55,6 +57,13 @@ const ( maxNodes = 32 // Arbitrary ) +// ConsensusStateSyncCfg is a node's consensus state sync configuration. +type ConsensusStateSyncCfg struct { + ConsensusNodes []string + TrustHeight uint64 + TrustHash string +} + // Node defines the common fields for all node types. type Node struct { // nolint: maligned sync.Mutex @@ -78,6 +87,7 @@ type Node struct { // nolint: maligned logWatcherHandlerFactories []log.WatcherHandlerFactory consensus ConsensusFixture + consensusStateSync *ConsensusStateSyncCfg customGrpcSocketPath string } @@ -189,6 +199,14 @@ func (n *Node) handleExit(cmdErr error) error { } } +// SetConsensusStateSync configures wheteher a node should perform +func (n *Node) SetConsensusStateSync(cfg *ConsensusStateSyncCfg) { + n.Lock() + defer n.Unlock() + + n.consensusStateSync = cfg +} + // NodeCfg defines the common node configuration options. type NodeCfg struct { // nolint: maligned AllowEarlyTermination bool @@ -257,14 +275,8 @@ type NetworkCfg struct { // nolint: maligned // RuntimeSGXLoaderBinary is the path to the Oasis SGX runtime loader. RuntimeSGXLoaderBinary string `json:"runtime_loader_binary"` - // ConsensusBackend is the consensus backend for all the nodes. - ConsensusBackend string `json:"consensus_backend"` - - // ConsensusTimeoutCommit is the consensus commit timeout. - ConsensusTimeoutCommit time.Duration `json:"consensus_timeout_commit"` - - // ConsensusGasCostsTxByte is the gas cost of each transaction byte. - ConsensusGasCostsTxByte uint64 `json:"consensus_gas_costs_tx_byte"` + // Consensus are the network-wide consensus parameters. + Consensus consensusGenesis.Genesis `json:"consensus"` // HaltEpoch is the halt epoch height flag. HaltEpoch uint64 `json:"halt_epoch"` @@ -739,6 +751,13 @@ func (net *Network) startOasisNode( extraArgs = extraArgs.debugDontBlameOasis() extraArgs = extraArgs.grpcDebugGrpcInternalSocketPath(node.customGrpcSocketPath) } + if node.consensusStateSync != nil { + extraArgs = extraArgs.tendermintStateSync( + node.consensusStateSync.ConsensusNodes, + node.consensusStateSync.TrustHeight, + node.consensusStateSync.TrustHash, + ) + } if viper.IsSet(metrics.CfgMetricsAddr) { extraArgs = extraArgs.appendNodeMetrics(node) } @@ -799,13 +818,15 @@ func (net *Network) makeGenesis() error { "--genesis.file", net.GenesisPath(), "--chain.id", genesisTestHelpers.TestChainID, "--halt.epoch", strconv.FormatUint(net.cfg.HaltEpoch, 10), - "--consensus.backend", net.cfg.ConsensusBackend, + "--consensus.backend", net.cfg.Consensus.Backend, "--epochtime.tendermint.interval", strconv.FormatInt(net.cfg.EpochtimeTendermintInterval, 10), - "--consensus.tendermint.timeout_commit", net.cfg.ConsensusTimeoutCommit.String(), + "--consensus.tendermint.timeout_commit", net.cfg.Consensus.Parameters.TimeoutCommit.String(), "--registry.debug.allow_unroutable_addresses", "true", "--" + genesis.CfgRegistryDebugAllowTestRuntimes, "true", "--scheduler.max_validators_per_entity", strconv.Itoa(len(net.Validators())), - "--" + genesis.CfgConsensusGasCostsTxByte, strconv.FormatUint(net.cfg.ConsensusGasCostsTxByte, 10), + "--" + genesis.CfgConsensusGasCostsTxByte, strconv.FormatUint(uint64(net.cfg.Consensus.Parameters.GasCosts[consensusGenesis.GasOpTxByte]), 10), + "--" + genesis.CfgConsensusStateCheckpointInterval, strconv.FormatUint(net.cfg.Consensus.Parameters.StateCheckpointInterval, 10), + "--" + genesis.CfgConsensusStateCheckpointNumKept, strconv.FormatUint(net.cfg.Consensus.Parameters.StateCheckpointNumKept, 10), "--" + genesis.CfgStakingTokenSymbol, genesisTestHelpers.TestStakingTokenSymbol, "--" + genesis.CfgStakingTokenValueExponent, strconv.FormatUint( uint64(genesisTestHelpers.TestStakingTokenValueExponent), 10), @@ -937,11 +958,14 @@ func New(env *env.Env, cfg *NetworkCfg) (*Network, error) { // Copy the config and apply some sane defaults. cfgCopy := *cfg - if cfgCopy.ConsensusBackend == "" { - cfgCopy.ConsensusBackend = defaultConsensusBackend + if cfgCopy.Consensus.Backend == "" { + cfgCopy.Consensus.Backend = defaultConsensusBackend + } + if cfgCopy.Consensus.Parameters.TimeoutCommit == 0 { + cfgCopy.Consensus.Parameters.TimeoutCommit = defaultConsensusTimeoutCommit } - if cfgCopy.ConsensusTimeoutCommit == 0 { - cfgCopy.ConsensusTimeoutCommit = defaultConsensusTimeoutCommit + if cfgCopy.Consensus.Parameters.GasCosts == nil { + cfgCopy.Consensus.Parameters.GasCosts = make(transaction.Costs) } if cfgCopy.EpochtimeTendermintInterval == 0 { cfgCopy.EpochtimeTendermintInterval = defaultEpochtimeTendermintInterval diff --git a/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go b/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go new file mode 100644 index 00000000000..a598b167c9c --- /dev/null +++ b/go/oasis-test-runner/scenario/e2e/consensus_state_sync.go @@ -0,0 +1,146 @@ +package e2e + +import ( + "context" + "encoding/hex" + "fmt" + "time" + + consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" + control "github.com/oasisprotocol/oasis-core/go/control/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" +) + +// ConsensusStateSync is the consensus state sync scenario. +var ConsensusStateSync scenario.Scenario = &consensusStateSyncImpl{ + E2E: *NewE2E("consensus-state-sync"), +} + +type consensusStateSyncImpl struct { + E2E +} + +func (sc *consensusStateSyncImpl) Clone() scenario.Scenario { + return &consensusStateSyncImpl{ + E2E: sc.E2E.Clone(), + } +} + +func (sc *consensusStateSyncImpl) Fixture() (*oasis.NetworkFixture, error) { + f, err := sc.E2E.Fixture() + if err != nil { + return nil, err + } + + // Enable checkpoints. + f.Network.Consensus.Parameters.StateCheckpointInterval = 10 + f.Network.Consensus.Parameters.StateCheckpointNumKept = 100 + f.Network.Consensus.Parameters.StateCheckpointChunkSize = 1024 * 1024 + // Add an extra validator. + f.Validators = append(f.Validators, + oasis.ValidatorFixture{Entity: 1, Consensus: oasis.ConsensusFixture{EnableConsensusRPCWorker: true}}, + ) + + return f, nil +} + +func (sc *consensusStateSyncImpl) Run(childEnv *env.Env) error { + if err := sc.Net.Start(); err != nil { + return err + } + + sc.Logger.Info("waiting for network to come up") + ctx := context.Background() + if err := sc.Net.Controller().WaitNodesRegistered(ctx, len(sc.Net.Validators())); err != nil { + return err + } + + // Stop one of the validators. + val := sc.Net.Validators()[2] + if err := val.Stop(); err != nil { + return fmt.Errorf("failed to stop validator: %w", err) + } + + // Let the network run for 50 blocks. This should generate some checkpoints. + blockCh, blockSub, err := sc.Net.Controller().Consensus.WatchBlocks(ctx) + if err != nil { + return err + } + defer blockSub.Close() + + sc.Logger.Info("waiting for some blocks") + var blk *consensus.Block + for { + select { + case blk = <-blockCh: + if blk.Height < 50 { + continue + } + case <-time.After(30 * time.Second): + return fmt.Errorf("timed out waiting for blocks") + } + + break + } + + sc.Logger.Info("got some blocks, starting the validator back", + "trust_height", blk.Height, + "trust_hash", hex.EncodeToString(blk.Hash), + ) + + // Get the TLS public key from the validators. + var consensusNodes []string + for _, v := range sc.Net.Validators()[:2] { + var ctrl *oasis.Controller + ctrl, err = oasis.NewController(v.SocketPath()) + if err != nil { + return fmt.Errorf("failed to create controller for validator %s: %w", v.Name, err) + } + + var status *control.Status + status, err = ctrl.GetStatus(ctx) + if err != nil { + return fmt.Errorf("failed to get status for validator %s: %w", v.Name, err) + } + + if status.Registration.Descriptor == nil { + return fmt.Errorf("validator %s has not registered", v.Name) + } + if len(status.Registration.Descriptor.TLS.Addresses) == 0 { + return fmt.Errorf("validator %s has no TLS addresses", v.Name) + } + + var rawAddress []byte + tlsAddress := status.Registration.Descriptor.TLS.Addresses[0] + rawAddress, err = tlsAddress.MarshalText() + if err != nil { + return fmt.Errorf("failed to marshal TLS address: %w", err) + } + consensusNodes = append(consensusNodes, string(rawAddress)) + } + + // Configure state sync for the consensus validator. + val.SetConsensusStateSync(&oasis.ConsensusStateSyncCfg{ + ConsensusNodes: consensusNodes, + TrustHeight: uint64(blk.Height), + TrustHash: hex.EncodeToString(blk.Hash), + }) + + if err = val.Start(); err != nil { + return fmt.Errorf("failed to start validator back: %w", err) + } + + // Wait for the validator to finish syncing. + sc.Logger.Info("waiting for the validator to sync") + valCtrl, err := oasis.NewController(val.SocketPath()) + if err != nil { + return err + } + if err = valCtrl.WaitSync(ctx); err != nil { + return err + } + + return nil +} diff --git a/go/oasis-test-runner/scenario/e2e/e2e.go b/go/oasis-test-runner/scenario/e2e/e2e.go index 21063e79432..ac53a0e27bb 100644 --- a/go/oasis-test-runner/scenario/e2e/e2e.go +++ b/go/oasis-test-runner/scenario/e2e/e2e.go @@ -10,6 +10,8 @@ import ( flag "github.com/spf13/pflag" "github.com/oasisprotocol/oasis-core/go/common/logging" + "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis" genesisFile "github.com/oasisprotocol/oasis-core/go/genesis/file" cmdCommon "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/common" cmdNode "github.com/oasisprotocol/oasis-core/go/oasis-node/cmd/node" @@ -86,8 +88,14 @@ func (sc *E2E) Fixture() (*oasis.NetworkFixture, error) { return &oasis.NetworkFixture{ Network: oasis.NetworkCfg{ - NodeBinary: nodeBinary, - ConsensusGasCostsTxByte: 1, + NodeBinary: nodeBinary, + Consensus: consensusGenesis.Genesis{ + Parameters: consensusGenesis.Parameters{ + GasCosts: transaction.Costs{ + consensusGenesis.GasOpTxByte: 1, + }, + }, + }, }, Entities: []oasis.EntityCfg{ {IsDebugTestEntity: true}, @@ -320,6 +328,8 @@ func RegisterScenarios() error { Debond, // Early query test. EarlyQuery, + // Consensus state sync. + ConsensusStateSync, } { if err := cmd.Register(s); err != nil { return err diff --git a/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go b/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go index c8a000e675b..3f87fe6614b 100644 --- a/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go +++ b/go/oasis-test-runner/scenario/e2e/gas_fees_staking.go @@ -9,6 +9,7 @@ import ( "github.com/oasisprotocol/oasis-core/go/common/quantity" consensus "github.com/oasisprotocol/oasis-core/go/consensus/api" "github.com/oasisprotocol/oasis-core/go/consensus/api/transaction" + consensusGenesis "github.com/oasisprotocol/oasis-core/go/consensus/genesis" "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" @@ -89,7 +90,13 @@ func (sc *gasFeesImpl) Fixture() (*oasis.NetworkFixture, error) { }, }, }, - ConsensusGasCostsTxByte: 0, // So we can control gas more easily. + Consensus: consensusGenesis.Genesis{ + Parameters: consensusGenesis.Parameters{ + GasCosts: transaction.Costs{ + consensusGenesis.GasOpTxByte: 0, // So we can control gas more easily. + }, + }, + }, }, Entities: []oasis.EntityCfg{ {IsDebugTestEntity: true}, diff --git a/go/oasis-test-runner/scenario/e2e/runtime/runtime.go b/go/oasis-test-runner/scenario/e2e/runtime/runtime.go index 18b3db10f43..69e32dafff0 100644 --- a/go/oasis-test-runner/scenario/e2e/runtime/runtime.go +++ b/go/oasis-test-runner/scenario/e2e/runtime/runtime.go @@ -130,7 +130,7 @@ func (sc *runtimeImpl) Fixture() (*oasis.NetworkFixture, error) { NodeBinary: f.Network.NodeBinary, RuntimeSGXLoaderBinary: runtimeLoader, DefaultLogWatcherHandlerFactories: DefaultRuntimeLogWatcherHandlerFactories, - ConsensusGasCostsTxByte: 1, + Consensus: f.Network.Consensus, IAS: oasis.IASCfg{ Mock: iasMock, },