diff --git a/abci/client/routed_client_test.go b/abci/client/routed_client_test.go index 54e765b0f9..99883da542 100644 --- a/abci/client/routed_client_test.go +++ b/abci/client/routed_client_test.go @@ -58,7 +58,8 @@ func TestRouting(t *testing.T) { consensusApp, consensusSocket := startApp(ctx, t, logger, "consensus") defer consensusApp.AssertExpectations(t) consensusApp.On("PrepareProposal", mock.Anything, mock.Anything).Return(&types.ResponsePrepareProposal{ - AppHash: []byte("apphash"), + AppHash: []byte("apphash"), + AppVersion: 1, }, nil).Once() consensusApp.On("FinalizeBlock", mock.Anything, mock.Anything).Return(&types.ResponseFinalizeBlock{ RetainHeight: 1, diff --git a/abci/cmd/abci-cli/abci-cli.go b/abci/cmd/abci-cli/abci-cli.go index 8dbb9697de..90cf1a373b 100644 --- a/abci/cmd/abci-cli/abci-cli.go +++ b/abci/cmd/abci-cli/abci-cli.go @@ -24,6 +24,7 @@ import ( "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/proto/tendermint/crypto" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + pbversion "github.com/dashpay/tenderdash/proto/tendermint/version" "github.com/dashpay/tenderdash/version" ) @@ -54,7 +55,7 @@ func RootCmmand(logger log.Logger) *cobra.Command { Use: "abci-cli", Short: "the ABCI CLI tool wraps an ABCI client", Long: "the ABCI CLI tool wraps an ABCI client and is used for testing ABCI servers", - PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) { + PersistentPreRunE: func(cmd *cobra.Command, _args []string) (err error) { switch cmd.Use { case "kvstore", "version": @@ -223,7 +224,7 @@ var versionCmd = &cobra.Command{ Short: "print ABCI console version", Long: "print ABCI console version", Args: cobra.ExactArgs(0), - RunE: func(cmd *cobra.Command, args []string) error { + RunE: func(_cmd *cobra.Command, _args []string) error { fmt.Println(version.ABCIVersion) return nil }, @@ -697,8 +698,9 @@ func cmdProcessProposal(cmd *cobra.Command, args []string) error { panic(err) } res, err := client.ProcessProposal(cmd.Context(), &types.RequestProcessProposal{ - Height: height, - Txs: txsBytesArray, + Height: height, + Txs: txsBytesArray, + Version: &pbversion.Consensus{Block: version.BlockProtocol, App: kvstore.ProtocolVersion}, }) if err != nil { return err @@ -711,7 +713,7 @@ func cmdProcessProposal(cmd *cobra.Command, args []string) error { } func makeKVStoreCmd(logger log.Logger) func(*cobra.Command, []string) error { - return func(cmd *cobra.Command, args []string) error { + return func(cmd *cobra.Command, _args []string) error { // Create the application - in memory or persisted to disk var ( app types.Application diff --git a/abci/example/counter/counter.go b/abci/example/counter/counter.go index 293e828f64..7e34923753 100644 --- a/abci/example/counter/counter.go +++ b/abci/example/counter/counter.go @@ -79,6 +79,7 @@ func (app *Application) PrepareProposal(_ context.Context, req *types.RequestPre AppHash: make([]byte, tmcrypto.DefaultAppHashSize), CoreChainLockUpdate: app.lastCoreChainLock.ToProto(), TxResults: app.lastTxResults, + AppVersion: 1, } return &resp, nil } diff --git a/abci/example/example_test.go b/abci/example/example_test.go index 07d0bf5135..600d3fa77d 100644 --- a/abci/example/example_test.go +++ b/abci/example/example_test.go @@ -20,6 +20,7 @@ import ( "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/libs/log" tmnet "github.com/dashpay/tenderdash/libs/net" + "github.com/dashpay/tenderdash/proto/tendermint/version" ) func TestKVStore(t *testing.T) { @@ -28,7 +29,7 @@ func TestKVStore(t *testing.T) { logger := log.NewNopLogger() t.Log("### Testing KVStore") - app, err := kvstore.NewMemoryApp(kvstore.WithLogger(logger)) + app, err := kvstore.NewMemoryApp(kvstore.WithLogger(logger), kvstore.WithAppVersion(0)) require.NoError(t, err) testBulk(ctx, t, logger, app) } @@ -73,7 +74,11 @@ func testBulk(ctx context.Context, t *testing.T, logger log.Logger, app types.Ap require.NoError(t, err) // Construct request - rpp := &types.RequestProcessProposal{Height: 1, Txs: make([][]byte, numDeliverTxs)} + rpp := &types.RequestProcessProposal{ + Height: 1, + Txs: make([][]byte, numDeliverTxs), + Version: &version.Consensus{App: 1}, + } for counter := 0; counter < numDeliverTxs; counter++ { rpp.Txs[counter] = []byte("test") } diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index c97e0a9cc6..608bc8be44 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -27,7 +27,9 @@ import ( "github.com/dashpay/tenderdash/version" ) -const ProtocolVersion uint64 = 0x12345678 +// ProtocolVersion defines initial protocol (app) version. +// App version is incremented on every block, to match current height. +const ProtocolVersion uint64 = 1 //--------------------------------------------------- @@ -85,6 +87,9 @@ type Application struct { offerSnapshot *offerSnapshot shouldCommitVerify bool + // appVersion returned in ResponsePrepareProposal. + // Special value of 0 means that it will be always set to current height. + appVersion uint64 } // WithCommitVerification enables commit verification @@ -95,6 +100,15 @@ func WithCommitVerification() OptFunc { } } +// WithAppVersion enables the application to enforce the app version to be equal to provided value. +// Special value of `0` means that app version will be always set to current block version. +func WithAppVersion(version uint64) OptFunc { + return func(app *Application) error { + app.appVersion = version + return nil + } +} + // WithValidatorSetUpdates defines initial validator set when creating Application func WithValidatorSetUpdates(validatorSetUpdates map[int64]abci.ValidatorSetUpdate) OptFunc { return func(app *Application) error { @@ -212,6 +226,7 @@ func newApplication(stateStore StoreFactory, opts ...OptFunc) (*Application, err verifyTx: verifyTx, execTx: execTx, shouldCommitVerify: false, + appVersion: ProtocolVersion, } for _, opt := range opts { @@ -287,7 +302,7 @@ func (app *Application) InitChain(_ context.Context, req *abci.RequestInitChain) if !ok { consensusParams = types1.ConsensusParams{ Version: &types1.VersionParams{ - AppVersion: ProtocolVersion, + AppVersion: uint64(app.LastCommittedState.GetHeight()) + 1, }, } } @@ -346,6 +361,7 @@ func (app *Application) PrepareProposal(_ context.Context, req *abci.RequestPrep ConsensusParamUpdates: app.getConsensusParamsUpdate(req.Height), CoreChainLockUpdate: coreChainLock, ValidatorSetUpdate: app.getValidatorSetUpdate(req.Height), + AppVersion: app.appVersionForHeight(req.Height), } if app.cfg.PrepareProposalDelayMS != 0 { @@ -374,6 +390,14 @@ func (app *Application) ProcessProposal(_ context.Context, req *abci.RequestProc }, err } + if req.Version.App != app.appVersionForHeight(req.Height) { + app.logger.Error("app version mismatch in process proposal request", + "version", req.Version.App, "expected", app.appVersionForHeight(req.Height), "height", roundState.GetHeight()) + return &abci.ResponseProcessProposal{ + Status: abci.ResponseProcessProposal_REJECT, + }, nil + } + resp := &abci.ResponseProcessProposal{ Status: abci.ResponseProcessProposal_ACCEPT, AppHash: roundState.GetAppHash(), @@ -555,6 +579,13 @@ func (app *Application) ApplySnapshotChunk(_ context.Context, req *abci.RequestA app.logger.Debug("ApplySnapshotChunk", "resp", resp) return resp, nil } +func (app *Application) appVersionForHeight(height int64) uint64 { + if app.appVersion == 0 { + return uint64(height) + } + + return app.appVersion +} func (app *Application) createSnapshot() error { height := app.LastCommittedState.GetHeight() @@ -580,10 +611,12 @@ func (app *Application) Info(_ context.Context, req *abci.RequestInfo) (*abci.Re app.mu.Lock() defer app.mu.Unlock() appHash := app.LastCommittedState.GetAppHash() + appVersion := app.appVersionForHeight(app.LastCommittedState.GetHeight() + 1) // we set app version to CURRENT height + resp := &abci.ResponseInfo{ Data: fmt.Sprintf("{\"appHash\":\"%s\"}", appHash.String()), Version: version.ABCIVersion, - AppVersion: ProtocolVersion, + AppVersion: appVersion, LastBlockHeight: app.LastCommittedState.GetHeight(), LastBlockAppHash: app.LastCommittedState.GetAppHash(), } diff --git a/abci/example/kvstore/kvstore_test.go b/abci/example/kvstore/kvstore_test.go index 95281a3914..5b91bef7d9 100644 --- a/abci/example/kvstore/kvstore_test.go +++ b/abci/example/kvstore/kvstore_test.go @@ -21,6 +21,7 @@ import ( "github.com/dashpay/tenderdash/libs/log" "github.com/dashpay/tenderdash/libs/service" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + pbversion "github.com/dashpay/tenderdash/proto/tendermint/version" tmtypes "github.com/dashpay/tenderdash/types" "github.com/dashpay/tenderdash/version" ) @@ -48,8 +49,9 @@ func testKVStore(ctx context.Context, t *testing.T, app types.Application, tx [] require.ErrorContains(t, err, "duplicate PrepareProposal call") reqProcess := &types.RequestProcessProposal{ - Txs: [][]byte{tx}, - Height: height, + Txs: [][]byte{tx}, + Height: height, + Version: &pbversion.Consensus{App: uint64(height)}, } respProcess, err := app.ProcessProposal(ctx, reqProcess) require.NoError(t, err) @@ -122,7 +124,9 @@ func TestPersistentKVStoreKV(t *testing.T) { dir := t.TempDir() logger := log.NewNopLogger() - kvstore, err := NewPersistentApp(DefaultConfig(dir), WithLogger(logger.With("module", "kvstore"))) + kvstore, err := NewPersistentApp(DefaultConfig(dir), + WithLogger(logger.With("module", "kvstore")), + WithAppVersion(0)) require.NoError(t, err) key := testKey @@ -157,7 +161,7 @@ func TestPersistentKVStoreInfo(t *testing.T) { dir := t.TempDir() logger := log.NewTestingLogger(t).With("module", "kvstore") - kvstore, err := NewPersistentApp(DefaultConfig(dir), WithLogger(logger)) + kvstore, err := NewPersistentApp(DefaultConfig(dir), WithLogger(logger), WithAppVersion(0)) require.NoError(t, err) defer kvstore.Close() @@ -241,7 +245,7 @@ func TestValUpdates(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() - kvstore, err := NewMemoryApp() + kvstore, err := NewMemoryApp(WithAppVersion(0)) require.NoError(t, err) // init with some validators @@ -283,9 +287,10 @@ func makeApplyBlock( } respProcessProposal, err := kvstore.ProcessProposal(ctx, &types.RequestProcessProposal{ - Hash: hash, - Height: height, - Txs: txs, + Hash: hash, + Height: height, + Txs: txs, + Version: &pbversion.Consensus{App: uint64(height)}, }) require.NoError(t, err) require.NotZero(t, respProcessProposal) @@ -368,7 +373,9 @@ func TestClientServer(t *testing.T) { logger := log.NewTestingLogger(t) // set up socket app - kvstore, err := NewMemoryApp(WithLogger(logger.With("module", "app"))) + kvstore, err := NewMemoryApp( + WithLogger(logger.With("module", "app")), + WithAppVersion(0)) require.NoError(t, err) client, server, err := makeSocketClientServer(ctx, t, logger, kvstore, "kvstore-socket") @@ -380,7 +387,7 @@ func TestClientServer(t *testing.T) { runClientTests(ctx, t, client) // set up grpc app - kvstore, err = NewMemoryApp() + kvstore, err = NewMemoryApp(WithAppVersion(0)) require.NoError(t, err) gclient, gserver, err := makeGRPCClientServer(ctx, t, logger, kvstore, "/tmp/kvstore-grpc") @@ -406,8 +413,9 @@ func runClientTests(ctx context.Context, t *testing.T, client abciclient.Client) func testClient(ctx context.Context, t *testing.T, app abciclient.Client, height int64, tx []byte, key, value string) { rpp, err := app.ProcessProposal(ctx, &types.RequestProcessProposal{ - Txs: [][]byte{tx}, - Height: height, + Txs: [][]byte{tx}, + Height: height, + Version: &pbversion.Consensus{App: uint64(height)}, }) require.NoError(t, err) require.NotZero(t, rpp) @@ -522,6 +530,7 @@ func newKvApp(ctx context.Context, t *testing.T, genesisHeight int64, opts ...Op WithValidatorSetUpdates(map[int64]types.ValidatorSetUpdate{ genesisHeight: RandValidatorSetUpdate(1), }), + WithAppVersion(0), } app, err := NewMemoryApp(append(defaultOpts, opts...)...) require.NoError(t, err) @@ -536,17 +545,17 @@ func newKvApp(ctx context.Context, t *testing.T, genesisHeight int64, opts ...Op return app } -func assertRespInfo(t *testing.T, expectHeight int64, expectAppHash tmbytes.HexBytes, actual types.ResponseInfo, msgs ...interface{}) { +func assertRespInfo(t *testing.T, expectLastBlockHeight int64, expectAppHash tmbytes.HexBytes, actual types.ResponseInfo, msgs ...interface{}) { t.Helper() if expectAppHash == nil { expectAppHash = make(tmbytes.HexBytes, tmcrypto.DefaultAppHashSize) } expected := types.ResponseInfo{ - LastBlockHeight: expectHeight, + LastBlockHeight: expectLastBlockHeight, LastBlockAppHash: expectAppHash, Version: version.ABCIVersion, - AppVersion: ProtocolVersion, + AppVersion: uint64(expectLastBlockHeight + 1), Data: fmt.Sprintf(`{"appHash":"%s"}`, expectAppHash.String()), } diff --git a/abci/types/application.go b/abci/types/application.go index 407c381ef7..fe7b60bca4 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -111,8 +111,9 @@ func (BaseApplication) PrepareProposal(_ context.Context, req *RequestPreparePro }) } return &ResponsePrepareProposal{TxRecords: trs, - AppHash: make([]byte, crypto.DefaultAppHashSize), - TxResults: txResults(req.Txs), + AppHash: make([]byte, crypto.DefaultAppHashSize), + TxResults: txResults(req.Txs), + AppVersion: 1, }, nil } diff --git a/abci/types/types.go b/abci/types/types.go index abf8fbcf82..f9623c9709 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -272,6 +272,9 @@ func (m *ResponsePrepareProposal) Validate() error { if !isValidApphash(m.AppHash) { return fmt.Errorf("apphash (%X) of size %d is invalid", m.AppHash, len(m.AppHash)) } + if m.AppVersion == 0 { + return fmt.Errorf("app version cannot be 0") + } return nil } diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 9ea388dac6..012078bcf3 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -602,7 +602,7 @@ var xxx_messageInfo_RequestFlush proto.InternalMessageInfo // // Used to sync Tenderdash with the application during a handshake that happens on startup. // The returned app_version will be included in the Header of every block. -// Tenderdsah expects last_block_app_hash and last_block_height to be updated during Commit, +// Tenderdash expects last_block_app_hash and last_block_height to be updated during Commit, // ensuring that Commit is never called twice for the same block height. type RequestInfo struct { Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` @@ -1270,6 +1270,7 @@ type RequestPrepareProposal struct { // Proposer's latest available app protocol version. ProposedAppVersion uint64 `protobuf:"varint,11,opt,name=proposed_app_version,json=proposedAppVersion,proto3" json:"proposed_app_version,omitempty"` // App and block version used to generate the block. + // App version included in the block can be modified by setting ResponsePrepareProposal.app_version. Version *version.Consensus `protobuf:"bytes,12,opt,name=version,proto3" json:"version,omitempty"` // quorum_hash contains hash of validator quorum that will sign the block QuorumHash []byte `protobuf:"bytes,13,opt,name=quorum_hash,json=quorumHash,proto3" json:"quorum_hash,omitempty"` @@ -1469,6 +1470,7 @@ type RequestProcessProposal struct { // Proposer's latest available app protocol version. ProposedAppVersion uint64 `protobuf:"varint,12,opt,name=proposed_app_version,json=proposedAppVersion,proto3" json:"proposed_app_version,omitempty"` // App and block version used to generate the block. + // App version MUST be verified by the app. Version *version.Consensus `protobuf:"bytes,13,opt,name=version,proto3" json:"version,omitempty"` // quorum_hash contains hash of validator quorum that will sign the block QuorumHash []byte `protobuf:"bytes,14,opt,name=quorum_hash,json=quorumHash,proto3" json:"quorum_hash,omitempty"` @@ -2909,6 +2911,8 @@ type ResponsePrepareProposal struct { CoreChainLockUpdate *types1.CoreChainLock `protobuf:"bytes,5,opt,name=core_chain_lock_update,json=coreChainLockUpdate,proto3" json:"core_chain_lock_update,omitempty"` // Changes to validator set that will be applied at next height. ValidatorSetUpdate *ValidatorSetUpdate `protobuf:"bytes,6,opt,name=validator_set_update,json=validatorSetUpdate,proto3" json:"validator_set_update,omitempty"` + // Application version that was used to create the current proposal. + AppVersion uint64 `protobuf:"varint,7,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"` } func (m *ResponsePrepareProposal) Reset() { *m = ResponsePrepareProposal{} } @@ -2986,6 +2990,13 @@ func (m *ResponsePrepareProposal) GetValidatorSetUpdate() *ValidatorSetUpdate { return nil } +func (m *ResponsePrepareProposal) GetAppVersion() uint64 { + if m != nil { + return m.AppVersion + } + return 0 +} + type ResponseProcessProposal struct { // `enum` that signals if the application finds the proposal valid. Status ResponseProcessProposal_ProposalStatus `protobuf:"varint,1,opt,name=status,proto3,enum=tendermint.abci.ResponseProcessProposal_ProposalStatus" json:"status,omitempty"` @@ -4309,237 +4320,238 @@ func init() { func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3678 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcd, 0x73, 0x1b, 0xd7, - 0x91, 0xc7, 0xe0, 0x1b, 0x8d, 0xaf, 0xe1, 0x23, 0x25, 0x41, 0x90, 0x44, 0xd2, 0xa3, 0xb5, 0x25, - 0xcb, 0x36, 0x69, 0x4b, 0x6b, 0xcb, 0x5e, 0x7b, 0xb7, 0x0a, 0x00, 0xa1, 0x05, 0x29, 0x8a, 0xa4, - 0x87, 0x20, 0x5d, 0x5e, 0xaf, 0x3d, 0x35, 0x04, 0x1e, 0x89, 0xb1, 0x00, 0xcc, 0x78, 0x66, 0x40, - 0x81, 0xbe, 0xee, 0xba, 0x2a, 0xe5, 0x93, 0xff, 0x01, 0xdf, 0x92, 0x63, 0xee, 0xa9, 0x1c, 0x92, - 0xca, 0xcd, 0xa9, 0x5c, 0x7c, 0xcc, 0x25, 0x8a, 0x4b, 0xbe, 0xa4, 0x72, 0xf3, 0x29, 0x97, 0x1c, - 0x52, 0xef, 0x63, 0xbe, 0x00, 0x0c, 0x3e, 0x2c, 0x57, 0xa5, 0x72, 0xc3, 0xeb, 0xd7, 0xdd, 0xf3, - 0x3e, 0xfa, 0x75, 0xf7, 0xfb, 0xf5, 0x03, 0x5c, 0xb3, 0x71, 0xbf, 0x8d, 0xcd, 0x9e, 0xd6, 0xb7, - 0x37, 0xd5, 0x93, 0x96, 0xb6, 0x69, 0x5f, 0x18, 0xd8, 0xda, 0x30, 0x4c, 0xdd, 0xd6, 0x51, 0xd1, - 0xeb, 0xdc, 0x20, 0x9d, 0xe5, 0x1b, 0x3e, 0xee, 0x96, 0x79, 0x61, 0xd8, 0xfa, 0xa6, 0x61, 0xea, - 0xfa, 0x29, 0xe3, 0x2f, 0xfb, 0x95, 0x51, 0x3d, 0x9b, 0x6d, 0xd5, 0xea, 0xf0, 0xce, 0xeb, 0x63, - 0x9d, 0x27, 0x5d, 0xbd, 0xf5, 0x38, 0xb4, 0xd7, 0x37, 0x90, 0x40, 0x2f, 0xff, 0xee, 0x63, 0x7c, - 0xe1, 0xf4, 0xde, 0x18, 0x93, 0x35, 0x54, 0x53, 0xed, 0x39, 0xdd, 0xab, 0xbe, 0xee, 0x73, 0x6c, - 0x5a, 0x9a, 0xde, 0x0f, 0x28, 0x5f, 0x3b, 0xd3, 0xf5, 0xb3, 0x2e, 0xde, 0xa4, 0xad, 0x93, 0xc1, - 0xe9, 0xa6, 0xad, 0xf5, 0xb0, 0x65, 0xab, 0x3d, 0x83, 0x33, 0xac, 0x9c, 0xe9, 0x67, 0x3a, 0xfd, - 0xb9, 0x49, 0x7e, 0x31, 0xaa, 0xf4, 0x45, 0x06, 0x52, 0x32, 0xfe, 0x6c, 0x80, 0x2d, 0x1b, 0xdd, - 0x85, 0x38, 0x6e, 0x75, 0xf4, 0x92, 0xb0, 0x2e, 0xdc, 0xce, 0xde, 0xbd, 0xbe, 0x31, 0xb2, 0x6e, - 0x1b, 0x9c, 0xaf, 0xde, 0xea, 0xe8, 0x8d, 0x88, 0x4c, 0x79, 0xd1, 0x9b, 0x90, 0x38, 0xed, 0x0e, - 0xac, 0x4e, 0x29, 0x4a, 0x85, 0x6e, 0x84, 0x09, 0x3d, 0x20, 0x4c, 0x8d, 0x88, 0xcc, 0xb8, 0xc9, - 0xa7, 0xb4, 0xfe, 0xa9, 0x5e, 0x8a, 0x4d, 0xff, 0xd4, 0x76, 0xff, 0x94, 0x7e, 0x8a, 0xf0, 0xa2, - 0x2a, 0x80, 0xd6, 0xd7, 0x6c, 0xa5, 0xd5, 0x51, 0xb5, 0x7e, 0x29, 0x4e, 0x25, 0x5f, 0x08, 0x97, - 0xd4, 0xec, 0x1a, 0x61, 0x6c, 0x44, 0xe4, 0x8c, 0xe6, 0x34, 0xc8, 0x70, 0x3f, 0x1b, 0x60, 0xf3, - 0xa2, 0x94, 0x98, 0x3e, 0xdc, 0xf7, 0x09, 0x13, 0x19, 0x2e, 0xe5, 0x46, 0xef, 0x41, 0xba, 0xd5, - 0xc1, 0xad, 0xc7, 0x8a, 0x3d, 0x2c, 0xa5, 0xa8, 0xe4, 0x5a, 0x98, 0x64, 0x8d, 0xf0, 0x35, 0x87, - 0x8d, 0x88, 0x9c, 0x6a, 0xb1, 0x9f, 0x68, 0x0f, 0x0a, 0x5d, 0xcd, 0xb2, 0x15, 0xab, 0xaf, 0x1a, - 0x56, 0x47, 0xb7, 0xad, 0x52, 0x96, 0xea, 0x78, 0x31, 0x4c, 0xc7, 0xae, 0x66, 0xd9, 0x87, 0x0e, - 0x73, 0x23, 0x22, 0xe7, 0xbb, 0x7e, 0x02, 0xd1, 0xa7, 0x9f, 0x9e, 0x62, 0xd3, 0x55, 0x58, 0xca, - 0x4d, 0xd7, 0xb7, 0x4f, 0xb8, 0x1d, 0x79, 0xa2, 0x4f, 0xf7, 0x13, 0xd0, 0x47, 0xb0, 0xdc, 0xd5, - 0xd5, 0xb6, 0xab, 0x4e, 0x69, 0x75, 0x06, 0xfd, 0xc7, 0xa5, 0x3c, 0x55, 0xfa, 0x72, 0xe8, 0x20, - 0x75, 0xb5, 0xed, 0xa8, 0xa8, 0x11, 0x81, 0x46, 0x44, 0x5e, 0xea, 0x8e, 0x12, 0xd1, 0x27, 0xb0, - 0xa2, 0x1a, 0x46, 0xf7, 0x62, 0x54, 0x7b, 0x81, 0x6a, 0xbf, 0x13, 0xa6, 0xbd, 0x42, 0x64, 0x46, - 0xd5, 0x23, 0x75, 0x8c, 0x8a, 0x9a, 0x20, 0x1a, 0x26, 0x36, 0x54, 0x13, 0x2b, 0x86, 0xa9, 0x1b, - 0xba, 0xa5, 0x76, 0x4b, 0x45, 0xaa, 0xfb, 0x56, 0x98, 0xee, 0x03, 0xc6, 0x7f, 0xc0, 0xd9, 0x1b, - 0x11, 0xb9, 0x68, 0x04, 0x49, 0x4c, 0xab, 0xde, 0xc2, 0x96, 0xe5, 0x69, 0x15, 0x67, 0x69, 0xa5, - 0xfc, 0x41, 0xad, 0x01, 0x12, 0xaa, 0x43, 0x16, 0x0f, 0x89, 0xb8, 0x72, 0xae, 0xdb, 0xb8, 0xb4, - 0x44, 0x15, 0x4a, 0xa1, 0xe7, 0x8c, 0xb2, 0x1e, 0xeb, 0x36, 0x6e, 0x44, 0x64, 0xc0, 0x6e, 0x0b, - 0xa9, 0x70, 0xe9, 0x1c, 0x9b, 0xda, 0xe9, 0x05, 0x55, 0xa3, 0xd0, 0x1e, 0xe2, 0x0f, 0x4a, 0x88, - 0x2a, 0x7c, 0x25, 0x4c, 0xe1, 0x31, 0x15, 0x22, 0x2a, 0xea, 0x8e, 0x48, 0x23, 0x22, 0x2f, 0x9f, - 0x8f, 0x93, 0x89, 0x89, 0x9d, 0x6a, 0x7d, 0xb5, 0xab, 0x7d, 0x8e, 0x15, 0xea, 0xe0, 0x4a, 0xcb, - 0xd3, 0x4d, 0xec, 0x01, 0xe7, 0xae, 0x12, 0x66, 0x62, 0x62, 0xa7, 0x7e, 0x42, 0x35, 0x05, 0x89, - 0x73, 0xb5, 0x3b, 0xc0, 0x3b, 0xf1, 0x74, 0x52, 0x4c, 0xed, 0xc4, 0xd3, 0x69, 0x31, 0xb3, 0x13, - 0x4f, 0x67, 0x44, 0xd8, 0x89, 0xa7, 0x41, 0xcc, 0x4a, 0xb7, 0x20, 0xeb, 0x73, 0x2f, 0xa8, 0x04, - 0xa9, 0x1e, 0xb6, 0x2c, 0xf5, 0x0c, 0x53, 0x6f, 0x94, 0x91, 0x9d, 0xa6, 0x54, 0x80, 0x9c, 0xdf, - 0xa5, 0x48, 0x5f, 0x09, 0xae, 0x24, 0xf1, 0x16, 0x44, 0x92, 0xbb, 0x47, 0x47, 0x92, 0x37, 0xd1, - 0x4d, 0xc8, 0xd3, 0xa9, 0x28, 0x4e, 0x3f, 0x71, 0x59, 0x71, 0x39, 0x47, 0x89, 0xc7, 0x9c, 0x69, - 0x0d, 0xb2, 0xc6, 0x5d, 0xc3, 0x65, 0x89, 0x51, 0x16, 0x30, 0xee, 0x1a, 0x0e, 0xc3, 0x0b, 0x90, - 0x23, 0xf3, 0x76, 0x39, 0xe2, 0xf4, 0x23, 0x59, 0x42, 0xe3, 0x2c, 0xd2, 0xff, 0xc7, 0x40, 0x1c, - 0x75, 0x43, 0xe8, 0x6d, 0x88, 0x13, 0x8f, 0xcc, 0x9d, 0x6b, 0x79, 0x83, 0xb9, 0xeb, 0x0d, 0xc7, - 0x5d, 0x6f, 0x34, 0x1d, 0x77, 0x5d, 0x4d, 0x7f, 0xf3, 0x74, 0x2d, 0xf2, 0xd5, 0x9f, 0xd7, 0x04, - 0x99, 0x4a, 0xa0, 0xab, 0xc4, 0xf9, 0xa8, 0x5a, 0x5f, 0xd1, 0xda, 0x74, 0xc8, 0x19, 0xe2, 0x59, - 0x54, 0xad, 0xbf, 0xdd, 0x46, 0xbb, 0x20, 0xb6, 0xf4, 0xbe, 0x85, 0xfb, 0xd6, 0xc0, 0x52, 0x58, - 0xb8, 0xe0, 0x2e, 0x35, 0xe0, 0x18, 0x59, 0x9c, 0xa8, 0x39, 0x9c, 0x07, 0x94, 0x51, 0x2e, 0xb6, - 0x82, 0x04, 0xb4, 0x07, 0xf9, 0x73, 0xb5, 0xab, 0xb5, 0x55, 0x5b, 0x37, 0x15, 0x0b, 0xdb, 0xdc, - 0xc7, 0xde, 0x1c, 0xdb, 0xf3, 0x63, 0x87, 0xeb, 0x10, 0xdb, 0x47, 0x46, 0x5b, 0xb5, 0x71, 0x35, - 0xfe, 0xcd, 0xd3, 0x35, 0x41, 0xce, 0x9d, 0xfb, 0x7a, 0xd0, 0x4b, 0x50, 0x54, 0x0d, 0x43, 0xb1, - 0x6c, 0xd5, 0xc6, 0xca, 0xc9, 0x85, 0x8d, 0x2d, 0xea, 0x76, 0x73, 0x72, 0x5e, 0x35, 0x8c, 0x43, - 0x42, 0xad, 0x12, 0x22, 0x7a, 0x11, 0x0a, 0xc4, 0x43, 0x6b, 0x6a, 0x57, 0xe9, 0x60, 0xed, 0xac, - 0x63, 0x97, 0x92, 0xeb, 0xc2, 0xed, 0x98, 0x9c, 0xe7, 0xd4, 0x06, 0x25, 0xa2, 0x0d, 0x58, 0x76, - 0xd8, 0x5a, 0xba, 0x89, 0x1d, 0x5e, 0xe2, 0x8f, 0xf3, 0xf2, 0x12, 0xef, 0xaa, 0xe9, 0x26, 0x66, - 0xfc, 0x52, 0xdb, 0xb5, 0x14, 0xea, 0xcd, 0x11, 0x82, 0x78, 0x5b, 0xb5, 0x55, 0xba, 0x03, 0x39, - 0x99, 0xfe, 0x26, 0x34, 0x43, 0xb5, 0x3b, 0x7c, 0x5d, 0xe9, 0x6f, 0x74, 0x19, 0x92, 0x5c, 0x75, - 0x8c, 0x0e, 0x83, 0xb7, 0xd0, 0x0a, 0x24, 0x0c, 0x53, 0x3f, 0xc7, 0x74, 0x59, 0xd2, 0x32, 0x6b, - 0x48, 0x32, 0x14, 0x82, 0x9e, 0x1f, 0x15, 0x20, 0x6a, 0x0f, 0xf9, 0x57, 0xa2, 0xf6, 0x10, 0xbd, - 0x0e, 0x71, 0xb2, 0x01, 0xf4, 0x1b, 0x85, 0x09, 0xb1, 0x8e, 0xcb, 0x35, 0x2f, 0x0c, 0x2c, 0x53, - 0x4e, 0xe9, 0x32, 0xac, 0x4c, 0x8a, 0x04, 0x52, 0xc7, 0xa5, 0x07, 0x3c, 0x3a, 0x7a, 0x13, 0xd2, - 0x6e, 0x28, 0x60, 0xf6, 0x75, 0x75, 0xec, 0x2b, 0x0e, 0xb3, 0xec, 0xb2, 0x12, 0xc3, 0x22, 0xfb, - 0xd3, 0x51, 0x79, 0xf8, 0xce, 0xc9, 0x29, 0xd5, 0x30, 0x1a, 0xaa, 0xd5, 0x91, 0xce, 0xa0, 0x14, - 0xe6, 0xe6, 0x7d, 0xeb, 0x23, 0xd0, 0xd3, 0xe1, 0xac, 0x8f, 0xef, 0xe4, 0x45, 0xe9, 0x9e, 0xb8, - 0x27, 0x8f, 0x5a, 0xf0, 0xa0, 0xff, 0x98, 0x58, 0x70, 0x8c, 0x7d, 0x88, 0xb6, 0xb7, 0xdb, 0x52, - 0x1b, 0xae, 0x86, 0x7a, 0xfc, 0x80, 0x9c, 0x10, 0x90, 0x23, 0x9b, 0xc1, 0xe2, 0x08, 0x1b, 0x38, - 0x6b, 0x90, 0xa1, 0x59, 0x74, 0xde, 0xf4, 0x33, 0x19, 0x99, 0xb7, 0xa4, 0x1f, 0xe2, 0x70, 0x79, - 0xb2, 0xf3, 0x47, 0xeb, 0x90, 0xeb, 0xa9, 0x43, 0xc5, 0x1e, 0x72, 0x0b, 0x15, 0xe8, 0x9e, 0x43, - 0x4f, 0x1d, 0x36, 0x87, 0xcc, 0x3c, 0x45, 0x88, 0xd9, 0x43, 0xab, 0x14, 0x5d, 0x8f, 0xdd, 0xce, - 0xc9, 0xe4, 0x27, 0x7a, 0x04, 0x4b, 0x5d, 0xbd, 0xa5, 0x76, 0x95, 0xae, 0x6a, 0xd9, 0x4a, 0x4b, - 0xef, 0xf5, 0x34, 0x9b, 0x9f, 0xbb, 0x6b, 0xe3, 0xdb, 0x4b, 0xbb, 0x89, 0x6f, 0xa2, 0x87, 0x24, - 0x22, 0x17, 0xa9, 0xec, 0xae, 0x6a, 0xd9, 0xac, 0x0b, 0x6d, 0x41, 0xb6, 0xa7, 0x59, 0x27, 0xb8, - 0xa3, 0x9e, 0x6b, 0xba, 0x59, 0x8a, 0xaf, 0xc7, 0x26, 0xe6, 0x44, 0x8f, 0x3c, 0x1e, 0xae, 0xc9, - 0x2f, 0xe6, 0xdb, 0x96, 0x44, 0xc0, 0x6c, 0x1d, 0xc7, 0x93, 0x5c, 0xd8, 0xf1, 0xbc, 0x0e, 0x2b, - 0x7d, 0x3c, 0xb4, 0x15, 0xf7, 0x50, 0x5b, 0xcc, 0x56, 0x52, 0x74, 0xc9, 0x11, 0xe9, 0x73, 0x3d, - 0x81, 0x45, 0xcc, 0x86, 0xec, 0x8a, 0xa9, 0x0f, 0xfa, 0xed, 0x52, 0x7a, 0x5d, 0xb8, 0x9d, 0x90, - 0x59, 0x03, 0xdd, 0x87, 0x12, 0x3d, 0xb0, 0xcc, 0x8b, 0x11, 0x6f, 0x8b, 0xdb, 0xce, 0xe9, 0xcd, - 0x50, 0x4b, 0xb9, 0x44, 0xfa, 0xa9, 0x9f, 0xdc, 0xa5, 0xbd, 0xfc, 0xc4, 0x6f, 0xc2, 0x0a, 0x8b, - 0xbe, 0xd8, 0x24, 0x61, 0x98, 0x6c, 0x12, 0x1d, 0x00, 0xd0, 0x01, 0x2c, 0x39, 0x7d, 0x07, 0xa6, - 0xde, 0x1c, 0xd2, 0xef, 0xbf, 0xee, 0x0a, 0xb4, 0x15, 0x62, 0xda, 0x8e, 0x3d, 0x66, 0xa9, 0xa1, - 0x22, 0xa7, 0xaf, 0x62, 0xb8, 0xee, 0xfc, 0xbe, 0x67, 0xb4, 0xb9, 0xf1, 0x94, 0x90, 0x77, 0x79, - 0xae, 0xd3, 0xb3, 0xe9, 0x35, 0xc8, 0x7e, 0x36, 0xd0, 0xcd, 0x41, 0x8f, 0x0d, 0x29, 0x4f, 0x87, - 0x04, 0x8c, 0x44, 0x8f, 0xd0, 0x6f, 0x13, 0x3e, 0x9b, 0x0b, 0xe6, 0x01, 0xdc, 0xa2, 0x04, 0xcf, - 0xa2, 0x0e, 0x7d, 0x03, 0xf7, 0x1b, 0x55, 0x74, 0x5e, 0xa3, 0x72, 0xe7, 0x16, 0x6e, 0x57, 0xb1, - 0x1f, 0x67, 0x57, 0x08, 0xe2, 0x74, 0x86, 0x71, 0xe6, 0x36, 0xc9, 0xef, 0x50, 0x5b, 0x73, 0xf7, - 0x3f, 0xe9, 0xdf, 0x7f, 0xc7, 0x02, 0x53, 0x3f, 0x99, 0x05, 0xa6, 0x43, 0x2d, 0xf0, 0x47, 0xdb, - 0x5a, 0x13, 0x2e, 0x8f, 0x08, 0x2a, 0x03, 0x1a, 0xda, 0xa8, 0xb5, 0x8d, 0x24, 0xfc, 0x4e, 0x40, - 0xf5, 0x29, 0x92, 0x97, 0x03, 0x7a, 0x59, 0x58, 0x0c, 0xb5, 0xe0, 0xec, 0xa2, 0x16, 0x9c, 0x9b, - 0xc7, 0x82, 0xf3, 0xcf, 0x63, 0xc1, 0x85, 0x31, 0x0b, 0x3e, 0x82, 0xa5, 0xb1, 0x54, 0xd4, 0x35, - 0x07, 0x61, 0xa2, 0x39, 0x44, 0x27, 0x9b, 0x43, 0xcc, 0x67, 0x0e, 0xd2, 0x77, 0x02, 0x94, 0xc3, - 0x33, 0xd2, 0x89, 0x1f, 0x78, 0x03, 0x2e, 0x79, 0x99, 0x89, 0x7f, 0x1d, 0x99, 0xf7, 0x47, 0x6e, - 0xa7, 0xb7, 0x90, 0x53, 0xa2, 0x38, 0x1b, 0x53, 0xdc, 0x6f, 0xa2, 0x8f, 0xa0, 0x18, 0xcc, 0xa5, - 0x49, 0xaa, 0x42, 0x8e, 0xcb, 0xbf, 0x8d, 0x1d, 0x17, 0x6f, 0x2d, 0xdc, 0x31, 0xcb, 0x85, 0x73, - 0x7f, 0xd3, 0x92, 0xfe, 0x10, 0x75, 0x23, 0x75, 0x20, 0x31, 0x46, 0xef, 0x40, 0x92, 0x9f, 0x6c, - 0x61, 0xde, 0x93, 0xcd, 0x05, 0x46, 0x4f, 0x73, 0xf4, 0xf9, 0x4e, 0x73, 0x6c, 0xe2, 0xf6, 0xc5, - 0x27, 0x2f, 0x55, 0xc2, 0xbf, 0x54, 0xaf, 0x41, 0x82, 0xdd, 0x08, 0x58, 0x40, 0xb9, 0x32, 0x7e, - 0x2e, 0xe8, 0x54, 0x65, 0xc6, 0x85, 0x2a, 0x90, 0x66, 0x59, 0xb7, 0xd6, 0xe6, 0x0e, 0xe0, 0x6a, - 0x88, 0xc4, 0xf6, 0x56, 0x35, 0xfb, 0xec, 0xe9, 0x5a, 0x8a, 0x37, 0xe4, 0x14, 0x95, 0xdb, 0x6e, - 0x4b, 0xbf, 0xcb, 0x40, 0x5a, 0xc6, 0x96, 0x41, 0x4c, 0x18, 0x55, 0x21, 0x83, 0x87, 0x2d, 0x6c, - 0xd8, 0x4e, 0x86, 0x3f, 0xf9, 0x06, 0xc5, 0xb8, 0xeb, 0x0e, 0x67, 0x23, 0x22, 0x7b, 0x62, 0xe8, - 0x1e, 0x07, 0x3a, 0xc2, 0x31, 0x0b, 0x2e, 0xee, 0x47, 0x3a, 0xde, 0x72, 0x90, 0x0e, 0x16, 0xe8, - 0x57, 0x43, 0xa5, 0x46, 0xa0, 0x8e, 0x7b, 0x1c, 0xea, 0x88, 0xcf, 0xf8, 0x58, 0x00, 0xeb, 0xa8, - 0x05, 0xb0, 0x8e, 0xc4, 0x8c, 0x69, 0x86, 0x80, 0x1d, 0x6f, 0x39, 0x60, 0x47, 0x72, 0xc6, 0x88, - 0x47, 0xd0, 0x8e, 0xff, 0x1c, 0x43, 0x3b, 0xd6, 0x43, 0x45, 0x27, 0xc0, 0x1d, 0xfb, 0x63, 0x70, - 0x47, 0x9a, 0x2a, 0x79, 0x29, 0x54, 0xc9, 0x0c, 0xbc, 0x63, 0x7f, 0x0c, 0xef, 0xc8, 0xcc, 0x50, - 0x38, 0x03, 0xf0, 0xf8, 0xdf, 0xc9, 0x80, 0x07, 0x84, 0x42, 0x12, 0x7c, 0x98, 0xf3, 0x21, 0x1e, - 0x4a, 0x08, 0xe2, 0x91, 0x0d, 0xbd, 0x9d, 0x33, 0xf5, 0x73, 0x43, 0x1e, 0x47, 0x13, 0x20, 0x0f, - 0x96, 0xbc, 0xdc, 0x0e, 0x55, 0x3e, 0x07, 0xe6, 0x71, 0x34, 0x01, 0xf3, 0xc8, 0xcf, 0x54, 0x3b, - 0x13, 0xf4, 0x78, 0x10, 0x04, 0x3d, 0x0a, 0x21, 0x77, 0x4a, 0xef, 0xc8, 0x86, 0xa0, 0x1e, 0x27, - 0x61, 0xa8, 0x07, 0x43, 0x7b, 0x5e, 0x0d, 0xd5, 0xb8, 0x00, 0xec, 0xb1, 0x3f, 0x06, 0x7b, 0x88, - 0x33, 0x2c, 0x6d, 0x4e, 0xdc, 0x43, 0x7a, 0x99, 0xc4, 0xd2, 0x11, 0xa7, 0x44, 0x1c, 0x2c, 0x36, - 0x4d, 0xdd, 0xe4, 0x48, 0x05, 0x6b, 0x48, 0xb7, 0xc9, 0xbd, 0xd5, 0x73, 0x40, 0x53, 0xb0, 0x90, - 0x22, 0xe4, 0x03, 0x4e, 0x47, 0xfa, 0x95, 0xe0, 0xc9, 0x52, 0x34, 0xc4, 0x7f, 0xe7, 0xcd, 0xf0, - 0x3b, 0xef, 0xc8, 0x3d, 0x2d, 0x13, 0xc8, 0x08, 0xfc, 0x39, 0x07, 0x07, 0x3f, 0x54, 0x2f, 0xd7, - 0xb8, 0x03, 0x4b, 0x34, 0x3b, 0x65, 0x1e, 0x3d, 0x10, 0x34, 0x8a, 0xa4, 0x83, 0xad, 0x02, 0x8b, - 0x1e, 0xaf, 0xc1, 0xb2, 0x8f, 0xd7, 0xbd, 0x68, 0x32, 0x04, 0x40, 0x74, 0xb9, 0x2b, 0xfc, 0xc6, - 0xf9, 0x97, 0xa8, 0xb7, 0x42, 0x1e, 0x6a, 0x32, 0x09, 0xe0, 0x10, 0x7e, 0x34, 0xc0, 0x11, 0x7e, - 0xe1, 0x45, 0x1f, 0xc1, 0x4a, 0x00, 0xfb, 0x70, 0x92, 0xbf, 0xd8, 0x62, 0x10, 0x48, 0xc4, 0x97, - 0x8b, 0xb8, 0x3d, 0xe8, 0x63, 0xb8, 0x46, 0xd3, 0xd8, 0x90, 0x04, 0x33, 0x3e, 0x5f, 0x82, 0x79, - 0x85, 0xe8, 0xa8, 0x4d, 0x48, 0x32, 0x43, 0x80, 0x91, 0x44, 0x18, 0x30, 0xf2, 0x37, 0xc1, 0xb3, - 0x1b, 0x17, 0x1a, 0x69, 0xe9, 0x6d, 0x66, 0x5f, 0x79, 0x99, 0xfe, 0x26, 0x97, 0x94, 0xae, 0x7e, - 0xc6, 0x4d, 0x84, 0xfc, 0x24, 0x5c, 0x2e, 0x68, 0x9f, 0xe1, 0x81, 0x6a, 0x05, 0x12, 0x5a, 0xbf, - 0x8d, 0x87, 0xdc, 0x0a, 0x58, 0x83, 0xc8, 0x3e, 0xc6, 0x17, 0x7c, 0xaf, 0xc9, 0x4f, 0xc2, 0x47, - 0x0f, 0x02, 0x8d, 0x45, 0x39, 0x99, 0x35, 0xd0, 0xdb, 0x90, 0xa1, 0x95, 0x17, 0x45, 0x37, 0x2c, - 0x1e, 0x6a, 0x02, 0x19, 0x11, 0xab, 0x92, 0x6c, 0x1c, 0x10, 0x9e, 0x7d, 0xc3, 0x92, 0xd3, 0x06, - 0xff, 0xe5, 0xcb, 0x59, 0xd2, 0x81, 0x9c, 0xe5, 0x3a, 0x64, 0xc8, 0xe8, 0x2d, 0x43, 0x6d, 0x61, - 0x1a, 0x26, 0x32, 0xb2, 0x47, 0x90, 0x7e, 0x23, 0x40, 0x71, 0x24, 0x72, 0x4d, 0x9c, 0xbb, 0x73, - 0x6c, 0xa2, 0x41, 0xa8, 0x68, 0x6c, 0xf6, 0x37, 0x00, 0xce, 0x54, 0x4b, 0x79, 0xa2, 0xf6, 0x6d, - 0xdc, 0xe6, 0x4b, 0x90, 0x39, 0x53, 0xad, 0x0f, 0x28, 0x21, 0x38, 0x98, 0xc4, 0xc8, 0x60, 0x7c, - 0x60, 0x45, 0xd2, 0x0f, 0x56, 0xa0, 0x32, 0xa4, 0x0d, 0x53, 0xd3, 0x4d, 0xcd, 0xbe, 0xa0, 0x6b, - 0x12, 0x93, 0xdd, 0xb6, 0x74, 0x00, 0x97, 0x26, 0x06, 0x4d, 0x74, 0x1f, 0x32, 0x5e, 0xbc, 0x15, - 0x68, 0x6e, 0x38, 0x05, 0x03, 0xf2, 0x78, 0xc9, 0x92, 0x5c, 0x9a, 0x18, 0x36, 0x51, 0x1d, 0x92, - 0x26, 0xb6, 0x06, 0x5d, 0x96, 0xab, 0x16, 0xee, 0xbe, 0x36, 0x5f, 0xb8, 0x25, 0xd4, 0x41, 0xd7, - 0x96, 0xb9, 0xb0, 0xf4, 0x09, 0x24, 0x19, 0x05, 0x65, 0x21, 0x75, 0xb4, 0xf7, 0x70, 0x6f, 0xff, - 0x83, 0x3d, 0x31, 0x82, 0x00, 0x92, 0x95, 0x5a, 0xad, 0x7e, 0xd0, 0x14, 0x05, 0x94, 0x81, 0x44, - 0xa5, 0xba, 0x2f, 0x37, 0xc5, 0x28, 0x21, 0xcb, 0xf5, 0x9d, 0x7a, 0xad, 0x29, 0xc6, 0xd0, 0x12, - 0xe4, 0xd9, 0x6f, 0xe5, 0xc1, 0xbe, 0xfc, 0xa8, 0xd2, 0x14, 0xe3, 0x3e, 0xd2, 0x61, 0x7d, 0x6f, - 0xab, 0x2e, 0x8b, 0x09, 0xe9, 0x0d, 0xb8, 0x1a, 0x1a, 0xa0, 0x3d, 0x98, 0x48, 0xf0, 0xc1, 0x44, - 0xd2, 0xb7, 0x51, 0x72, 0x03, 0x09, 0x8b, 0xba, 0x68, 0x67, 0x64, 0xe2, 0x77, 0x17, 0x08, 0xd9, - 0x23, 0xb3, 0x47, 0x2f, 0x42, 0xc1, 0xc4, 0xa7, 0xd8, 0x6e, 0x75, 0x58, 0x16, 0xe0, 0xe0, 0x48, - 0x79, 0x4e, 0xa5, 0x42, 0x16, 0x63, 0xfb, 0x14, 0xb7, 0x6c, 0x85, 0x19, 0x81, 0x45, 0x6f, 0xeb, - 0x19, 0xc2, 0x46, 0xa8, 0x87, 0x8c, 0x48, 0x1c, 0x34, 0x73, 0x24, 0x4c, 0x55, 0x9c, 0xaa, 0x02, - 0xea, 0x17, 0x28, 0x45, 0x7a, 0xb2, 0xd0, 0x62, 0x67, 0x20, 0x21, 0xd7, 0x9b, 0xf2, 0x87, 0x62, - 0x0c, 0x21, 0x28, 0xd0, 0x9f, 0xca, 0xe1, 0x5e, 0xe5, 0xe0, 0xb0, 0xb1, 0x4f, 0x16, 0x7b, 0x19, - 0x8a, 0xce, 0x62, 0x3b, 0xc4, 0x04, 0xba, 0x04, 0x4b, 0xb5, 0xfd, 0x47, 0x07, 0xbb, 0xf5, 0x66, - 0xdd, 0x23, 0x27, 0xa5, 0x5f, 0xc7, 0xe0, 0x4a, 0x48, 0xae, 0x81, 0xde, 0x06, 0xb0, 0x87, 0x8a, - 0x89, 0x5b, 0xba, 0xd9, 0x0e, 0x37, 0xce, 0xe6, 0x50, 0xa6, 0x1c, 0x72, 0xc6, 0xe6, 0xbf, 0xa6, - 0x3a, 0xec, 0xf7, 0xb8, 0x52, 0x32, 0x59, 0x8b, 0x63, 0x1b, 0x37, 0x26, 0x5c, 0xd6, 0x70, 0x8b, - 0x28, 0xa6, 0x7b, 0x42, 0x15, 0x53, 0x7e, 0xf4, 0x21, 0x5c, 0x19, 0x89, 0x2b, 0xdc, 0x19, 0x5b, - 0x93, 0x0a, 0x8b, 0x93, 0xc3, 0xcb, 0xa5, 0x60, 0x78, 0x61, 0xce, 0xd8, 0x9a, 0x02, 0x24, 0x24, - 0x9e, 0x03, 0x48, 0x08, 0x8b, 0x4f, 0xc9, 0x45, 0x21, 0xfa, 0x09, 0xf1, 0x49, 0xfa, 0x7b, 0x60, - 0xf3, 0x82, 0xe9, 0xdb, 0x3e, 0x24, 0x2d, 0x5b, 0xb5, 0x07, 0x16, 0x3f, 0x0c, 0xf7, 0xe7, 0xcd, - 0x05, 0x37, 0x9c, 0x1f, 0x87, 0x54, 0x5c, 0xe6, 0x6a, 0xfe, 0x25, 0xf7, 0x34, 0x6c, 0xf5, 0x13, - 0x3f, 0xc1, 0xea, 0xa3, 0x06, 0x24, 0xf1, 0x39, 0xee, 0xdb, 0x56, 0x29, 0x49, 0x67, 0x7c, 0x79, - 0x7c, 0xc6, 0xa4, 0xbb, 0x5a, 0x22, 0xf9, 0xc5, 0x5f, 0x9f, 0xae, 0x89, 0x8c, 0xfb, 0x55, 0xbd, - 0xa7, 0xd9, 0xb8, 0x67, 0xd8, 0x17, 0x32, 0x97, 0x97, 0xde, 0x84, 0x42, 0x70, 0xd1, 0xc3, 0xbd, - 0x80, 0xe7, 0x67, 0xa3, 0xd2, 0x2f, 0x05, 0x58, 0x9e, 0x80, 0x6a, 0xa0, 0xfb, 0xbc, 0x70, 0xc1, - 0x36, 0xfe, 0xe6, 0xf8, 0xea, 0x05, 0xd8, 0xbd, 0xfa, 0x05, 0x89, 0x7b, 0x5e, 0x7a, 0xce, 0xf6, - 0xd8, 0x23, 0xa0, 0x57, 0xa0, 0x68, 0x69, 0x67, 0x7d, 0xc5, 0x64, 0x00, 0x89, 0x5b, 0x14, 0x20, - 0xd9, 0x33, 0xe9, 0x70, 0x4a, 0x67, 0xed, 0x9f, 0x09, 0x42, 0x15, 0x81, 0xa8, 0x8c, 0x70, 0x4b, - 0x2d, 0x40, 0xe3, 0xb7, 0x85, 0x49, 0x10, 0x8e, 0xf0, 0x1c, 0x10, 0xce, 0x2f, 0x04, 0xb8, 0x36, - 0xe5, 0x06, 0x81, 0xde, 0x1f, 0x39, 0x17, 0xef, 0x2c, 0x72, 0xff, 0xd8, 0x60, 0xb4, 0xe0, 0xc9, - 0x90, 0xee, 0x41, 0xce, 0x4f, 0x9f, 0x6f, 0xf3, 0x76, 0xbc, 0xf0, 0x1d, 0x84, 0x9a, 0x6e, 0x42, - 0xde, 0xc4, 0x36, 0xf1, 0x41, 0x01, 0x6c, 0x2e, 0xc7, 0x88, 0x2c, 0x15, 0xdc, 0x89, 0xa7, 0x05, - 0x31, 0xea, 0xda, 0xcf, 0xef, 0x05, 0x00, 0x0f, 0x7f, 0xf2, 0xf0, 0x1f, 0xc1, 0x8f, 0xff, 0x8c, - 0xc0, 0x86, 0xd1, 0x51, 0xd8, 0x10, 0xdd, 0x82, 0x22, 0xcb, 0xf9, 0xc9, 0xbe, 0xa9, 0xf6, 0xc0, - 0xc4, 0x1c, 0x6d, 0x2a, 0x50, 0xf2, 0xa1, 0x43, 0x45, 0x1f, 0xc1, 0x55, 0xbb, 0x63, 0x62, 0xab, - 0xa3, 0x77, 0xdb, 0xca, 0xe8, 0xde, 0xb1, 0x2a, 0xc8, 0xda, 0x0c, 0xa3, 0x93, 0xaf, 0xb8, 0x1a, - 0x8e, 0x83, 0xfb, 0xf7, 0x39, 0x24, 0xe8, 0xb1, 0x21, 0x79, 0x9b, 0x6b, 0xc5, 0x19, 0x6e, 0xa0, - 0x1f, 0x03, 0xa8, 0xb6, 0x6d, 0x6a, 0x27, 0x03, 0xe2, 0x1d, 0xa2, 0xe3, 0x9f, 0xf2, 0x8e, 0x5d, - 0xc5, 0xe1, 0xab, 0x5e, 0xe7, 0xe7, 0x6f, 0xc5, 0x13, 0xf5, 0x9d, 0x41, 0x9f, 0x42, 0x69, 0x0f, - 0x0a, 0x41, 0x59, 0x27, 0x21, 0x66, 0x63, 0x08, 0x26, 0xc4, 0x2c, 0xc1, 0xe6, 0x09, 0xb1, 0x9b, - 0x4e, 0xc7, 0x58, 0x8d, 0x91, 0x36, 0xa4, 0x1f, 0x04, 0xc8, 0xf9, 0xbd, 0xde, 0xdc, 0x39, 0x2b, - 0xcf, 0xe1, 0x63, 0xe3, 0x39, 0x7c, 0xdc, 0x97, 0xc5, 0x5e, 0x85, 0x34, 0xc9, 0x62, 0x07, 0x16, - 0x6e, 0xf3, 0xca, 0x6b, 0xea, 0x4c, 0xb5, 0x8e, 0x2c, 0xdc, 0xf6, 0xf9, 0xa6, 0xd4, 0xf3, 0xf9, - 0xa6, 0x60, 0x2e, 0x9c, 0x1e, 0xc9, 0x85, 0x77, 0xe2, 0xe9, 0x84, 0x98, 0x94, 0x7d, 0xc9, 0xb4, - 0xf4, 0x85, 0x00, 0x69, 0x77, 0xbe, 0xc1, 0x92, 0x63, 0x00, 0xa1, 0x64, 0xcb, 0xc5, 0x0a, 0x8e, - 0xfc, 0xf6, 0xc1, 0x0a, 0xb0, 0x31, 0xb7, 0x00, 0xfb, 0xae, 0x9b, 0xcf, 0x85, 0x61, 0x70, 0xfe, - 0xc5, 0x75, 0x60, 0x57, 0x9e, 0xbe, 0xfe, 0x9c, 0x8f, 0x83, 0x24, 0x24, 0xe8, 0x3f, 0x20, 0xa9, - 0xb6, 0x5c, 0xe4, 0xb1, 0x30, 0x01, 0x92, 0x73, 0x58, 0x37, 0x9a, 0xc3, 0x0a, 0xe5, 0x94, 0xb9, - 0x04, 0x1f, 0x55, 0xd4, 0x19, 0x95, 0xb4, 0x4b, 0xf4, 0x32, 0x9e, 0xe0, 0x49, 0x2f, 0x00, 0x1c, - 0xed, 0x3d, 0xda, 0xdf, 0xda, 0x7e, 0xb0, 0x5d, 0xdf, 0xe2, 0x09, 0xdb, 0xd6, 0x56, 0x7d, 0x4b, - 0x8c, 0x12, 0x3e, 0xb9, 0xfe, 0x68, 0xff, 0xb8, 0xbe, 0x25, 0xc6, 0x48, 0x63, 0xab, 0xbe, 0x5b, - 0xf9, 0xb0, 0xbe, 0x25, 0xc6, 0xa5, 0x0a, 0x64, 0xdc, 0xa0, 0x43, 0x2b, 0xd5, 0xfa, 0x13, 0x6c, - 0xf2, 0xd5, 0x62, 0x0d, 0xb4, 0x0a, 0xd9, 0x71, 0xe8, 0x9c, 0xdc, 0xbf, 0x18, 0x62, 0x4e, 0xc2, - 0x40, 0xd1, 0xd5, 0xc1, 0x63, 0xd3, 0xbb, 0x90, 0x32, 0x06, 0x27, 0x8a, 0x63, 0xbb, 0x23, 0x80, - 0xb3, 0x73, 0x3d, 0x1b, 0x9c, 0x74, 0xb5, 0xd6, 0x43, 0x7c, 0xc1, 0x83, 0x5c, 0xd2, 0x18, 0x9c, - 0x3c, 0x64, 0x26, 0xce, 0x86, 0x11, 0x9d, 0x32, 0x8c, 0xd8, 0xc8, 0x30, 0xd0, 0x2d, 0xc8, 0xf5, - 0xf5, 0x36, 0x56, 0xd4, 0x76, 0xdb, 0xc4, 0x16, 0x8b, 0xdd, 0x19, 0xae, 0x39, 0x4b, 0x7a, 0x2a, - 0xac, 0x43, 0xfa, 0x4e, 0x00, 0x34, 0x1e, 0x68, 0xd1, 0x21, 0x2c, 0x79, 0xb1, 0xda, 0x49, 0x00, - 0x58, 0x24, 0x58, 0x0f, 0x0f, 0xd4, 0x81, 0x3b, 0xbc, 0x78, 0x1e, 0x24, 0x93, 0xa4, 0x6e, 0xc5, - 0x73, 0x55, 0x06, 0x9d, 0x2f, 0x5d, 0x94, 0xe8, 0x9c, 0x8b, 0x12, 0x91, 0x91, 0x2b, 0xef, 0xf6, - 0x8c, 0xba, 0xd2, 0xd8, 0x58, 0x05, 0xc6, 0x80, 0x52, 0x73, 0x4c, 0x8c, 0xcf, 0x33, 0x6c, 0x48, - 0xc2, 0xf3, 0x0c, 0x49, 0xba, 0x07, 0xe2, 0xfb, 0xee, 0xf7, 0xf9, 0x97, 0x46, 0x86, 0x29, 0x8c, - 0x0d, 0xf3, 0x1c, 0xd2, 0xc4, 0xfb, 0xd2, 0xa0, 0xf1, 0x5f, 0x90, 0x71, 0x57, 0xcf, 0x7d, 0xec, - 0x12, 0xba, 0xec, 0x7c, 0x24, 0x9e, 0x08, 0xba, 0x03, 0x4b, 0x24, 0x6e, 0x38, 0x75, 0x50, 0x86, - 0xc2, 0x45, 0xa9, 0x37, 0x2c, 0xb2, 0x8e, 0x5d, 0x07, 0x3a, 0x22, 0x31, 0x5a, 0x64, 0xb1, 0x1c, - 0xb7, 0xff, 0x19, 0x03, 0x20, 0xd7, 0xb6, 0x11, 0x30, 0x92, 0xed, 0x61, 0x3e, 0x90, 0x4c, 0x48, - 0xff, 0x17, 0x85, 0xac, 0xaf, 0x2e, 0x83, 0xfe, 0x3d, 0x90, 0x58, 0xad, 0x4f, 0xab, 0xe1, 0xf8, - 0xb2, 0xaa, 0xc0, 0xc4, 0xa2, 0x8b, 0x4f, 0x2c, 0xac, 0x22, 0xe6, 0x94, 0x67, 0xe3, 0x0b, 0x97, - 0x67, 0x5f, 0x05, 0x64, 0xeb, 0xb6, 0xda, 0x25, 0xc1, 0x5b, 0xeb, 0x9f, 0x29, 0xec, 0xb4, 0xb3, - 0x92, 0xb0, 0x48, 0x7b, 0x8e, 0x69, 0xc7, 0x01, 0xa1, 0x4b, 0x5d, 0x48, 0xbb, 0xd8, 0xc2, 0xe2, - 0x6f, 0x48, 0x26, 0x95, 0xa1, 0xcb, 0x90, 0xee, 0x61, 0x5b, 0xa5, 0x61, 0x8f, 0x61, 0x4d, 0x6e, - 0xfb, 0xce, 0x3b, 0x90, 0xf5, 0x3d, 0xac, 0x21, 0x91, 0x70, 0xaf, 0xfe, 0x81, 0x18, 0x29, 0xa7, - 0xbe, 0xfc, 0x7a, 0x3d, 0xb6, 0x87, 0x9f, 0x90, 0x4f, 0xc9, 0xf5, 0x5a, 0xa3, 0x5e, 0x7b, 0x28, - 0x0a, 0xe5, 0xec, 0x97, 0x5f, 0xaf, 0xa7, 0x64, 0x4c, 0x4b, 0x18, 0x77, 0x1e, 0x42, 0x71, 0x64, - 0x07, 0x82, 0x0e, 0x1a, 0x41, 0x61, 0xeb, 0xe8, 0x60, 0x77, 0xbb, 0x56, 0x69, 0xd6, 0x95, 0xe3, - 0xfd, 0x66, 0x5d, 0x14, 0xd0, 0x15, 0x58, 0xde, 0xdd, 0xfe, 0xef, 0x46, 0x53, 0xa9, 0xed, 0x6e, - 0xd7, 0xf7, 0x9a, 0x4a, 0xa5, 0xd9, 0xac, 0xd4, 0x1e, 0x8a, 0xd1, 0xbb, 0x7f, 0x02, 0x28, 0x56, - 0xaa, 0xb5, 0xed, 0x8a, 0x61, 0x74, 0xb5, 0x96, 0x4a, 0xdd, 0x7d, 0x0d, 0xe2, 0x14, 0xd9, 0x9d, - 0xfa, 0xc4, 0xb6, 0x3c, 0xbd, 0x2e, 0x85, 0x1e, 0x40, 0x82, 0x82, 0xbe, 0x68, 0xfa, 0x9b, 0xdb, - 0xf2, 0x8c, 0x42, 0x15, 0x19, 0x0c, 0x3d, 0x37, 0x53, 0x1f, 0xe1, 0x96, 0xa7, 0xd7, 0xad, 0xd0, - 0x2e, 0xa4, 0x1c, 0x3c, 0x6d, 0xd6, 0xcb, 0xd8, 0xf2, 0xcc, 0x62, 0x12, 0x99, 0x1a, 0xc3, 0x25, - 0xa7, 0xbf, 0xcf, 0x2d, 0xcf, 0xa8, 0x68, 0x21, 0x19, 0x32, 0x1e, 0x94, 0x3c, 0xfb, 0xa9, 0x70, - 0x79, 0x8e, 0x0a, 0x1b, 0xfa, 0x04, 0xf2, 0x41, 0xe4, 0x6d, 0xbe, 0x57, 0xbc, 0xe5, 0x39, 0xab, - 0x5f, 0x44, 0x7f, 0x10, 0x86, 0x9b, 0xef, 0x55, 0x6f, 0x79, 0xce, 0x62, 0x18, 0xfa, 0x14, 0x96, - 0xc6, 0x61, 0xb2, 0xf9, 0x1f, 0xf9, 0x96, 0x17, 0x28, 0x8f, 0xa1, 0x1e, 0xa0, 0x09, 0xf0, 0xda, - 0x02, 0x6f, 0x7e, 0xcb, 0x8b, 0x54, 0xcb, 0x50, 0x1b, 0x8a, 0xa3, 0xd0, 0xd3, 0xbc, 0x6f, 0x80, - 0xcb, 0x73, 0x57, 0xce, 0xd8, 0x57, 0x82, 0x18, 0xc9, 0xbc, 0x6f, 0x82, 0xcb, 0x73, 0x17, 0xd2, - 0xd0, 0x11, 0x80, 0xef, 0x6e, 0x3b, 0xc7, 0x1b, 0xe1, 0xf2, 0x3c, 0x25, 0x35, 0x64, 0xc0, 0xf2, - 0xa4, 0xcb, 0xec, 0x22, 0x4f, 0x86, 0xcb, 0x0b, 0x55, 0xda, 0x88, 0x3d, 0x07, 0xef, 0xa5, 0xf3, - 0x3d, 0x21, 0x2e, 0xcf, 0x59, 0x72, 0xab, 0x56, 0xbf, 0x79, 0xb6, 0x2a, 0x7c, 0xfb, 0x6c, 0x55, - 0xf8, 0xee, 0xd9, 0xaa, 0xf0, 0xd5, 0xf7, 0xab, 0x91, 0x6f, 0xbf, 0x5f, 0x8d, 0xfc, 0xf1, 0xfb, - 0xd5, 0xc8, 0xff, 0xdc, 0x3e, 0xd3, 0xec, 0xce, 0xe0, 0x64, 0xa3, 0xa5, 0xf7, 0xe8, 0x3f, 0x38, - 0x0c, 0xf5, 0x62, 0x93, 0xe9, 0x24, 0x2d, 0xdf, 0xff, 0x44, 0x4e, 0x92, 0x34, 0xd6, 0xdd, 0xfb, - 0x47, 0x00, 0x00, 0x00, 0xff, 0xff, 0x94, 0x62, 0x2f, 0xa1, 0x47, 0x32, 0x00, 0x00, + // 3682 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xd4, 0x5b, 0xcb, 0x73, 0x1b, 0x47, + 0x73, 0xc7, 0xe2, 0x8d, 0xc6, 0x6b, 0x39, 0xa4, 0x24, 0x08, 0x92, 0x48, 0x7a, 0x15, 0x5b, 0xb2, + 0x6c, 0x93, 0xb6, 0x14, 0x5b, 0x76, 0xec, 0xa4, 0x0a, 0x04, 0xa1, 0x80, 0x14, 0x45, 0xd2, 0x4b, + 0x90, 0x2e, 0xc7, 0xb1, 0xb7, 0x96, 0xc0, 0x90, 0x58, 0x0b, 0xc0, 0xae, 0x77, 0x17, 0x14, 0xe8, + 0x6b, 0xe2, 0xaa, 0x94, 0x4f, 0xfe, 0x07, 0x7c, 0x4b, 0x8e, 0xb9, 0xe7, 0x94, 0x54, 0x6e, 0x4e, + 0xe5, 0xe2, 0x63, 0xaa, 0x52, 0x51, 0x5c, 0xf2, 0x25, 0x95, 0x9b, 0x4f, 0xdf, 0xe5, 0x3b, 0x7c, + 0x35, 0x8f, 0x7d, 0x02, 0x8b, 0x87, 0xe5, 0xaa, 0xaf, 0xbe, 0x1b, 0xa6, 0xa7, 0xbb, 0x77, 0x1e, + 0x3d, 0xdd, 0x3d, 0xbf, 0x1e, 0xc0, 0x0d, 0x1b, 0x0f, 0x3a, 0xd8, 0xec, 0x6b, 0x03, 0x7b, 0x53, + 0x3d, 0x6d, 0x6b, 0x9b, 0xf6, 0xa5, 0x81, 0xad, 0x0d, 0xc3, 0xd4, 0x6d, 0x1d, 0x95, 0xbd, 0xce, + 0x0d, 0xd2, 0x59, 0xbd, 0xe5, 0xe3, 0x6e, 0x9b, 0x97, 0x86, 0xad, 0x6f, 0x1a, 0xa6, 0xae, 0x9f, + 0x31, 0xfe, 0xaa, 0x5f, 0x19, 0xd5, 0xb3, 0xd9, 0x51, 0xad, 0x2e, 0xef, 0xbc, 0x39, 0xd6, 0x79, + 0xda, 0xd3, 0xdb, 0x4f, 0x23, 0x7b, 0x7d, 0x03, 0x09, 0xf4, 0xf2, 0xef, 0x3e, 0xc5, 0x97, 0x4e, + 0xef, 0xad, 0x31, 0x59, 0x43, 0x35, 0xd5, 0xbe, 0xd3, 0xbd, 0xea, 0xeb, 0xbe, 0xc0, 0xa6, 0xa5, + 0xe9, 0x83, 0x80, 0xf2, 0xb5, 0x73, 0x5d, 0x3f, 0xef, 0xe1, 0x4d, 0xda, 0x3a, 0x1d, 0x9e, 0x6d, + 0xda, 0x5a, 0x1f, 0x5b, 0xb6, 0xda, 0x37, 0x38, 0xc3, 0xca, 0xb9, 0x7e, 0xae, 0xd3, 0x9f, 0x9b, + 0xe4, 0x17, 0xa3, 0x4a, 0xdf, 0xe4, 0x20, 0x23, 0xe3, 0xaf, 0x86, 0xd8, 0xb2, 0xd1, 0x7d, 0x48, + 0xe2, 0x76, 0x57, 0xaf, 0x08, 0xeb, 0xc2, 0xdd, 0xfc, 0xfd, 0x9b, 0x1b, 0xa1, 0x75, 0xdb, 0xe0, + 0x7c, 0x8d, 0x76, 0x57, 0x6f, 0xc6, 0x64, 0xca, 0x8b, 0xde, 0x85, 0xd4, 0x59, 0x6f, 0x68, 0x75, + 0x2b, 0x71, 0x2a, 0x74, 0x2b, 0x4a, 0xe8, 0x11, 0x61, 0x6a, 0xc6, 0x64, 0xc6, 0x4d, 0x3e, 0xa5, + 0x0d, 0xce, 0xf4, 0x4a, 0x62, 0xfa, 0xa7, 0x76, 0x06, 0x67, 0xf4, 0x53, 0x84, 0x17, 0x6d, 0x01, + 0x68, 0x03, 0xcd, 0x56, 0xda, 0x5d, 0x55, 0x1b, 0x54, 0x92, 0x54, 0xf2, 0x95, 0x68, 0x49, 0xcd, + 0xae, 0x13, 0xc6, 0x66, 0x4c, 0xce, 0x69, 0x4e, 0x83, 0x0c, 0xf7, 0xab, 0x21, 0x36, 0x2f, 0x2b, + 0xa9, 0xe9, 0xc3, 0xfd, 0x98, 0x30, 0x91, 0xe1, 0x52, 0x6e, 0xf4, 0x11, 0x64, 0xdb, 0x5d, 0xdc, + 0x7e, 0xaa, 0xd8, 0xa3, 0x4a, 0x86, 0x4a, 0xae, 0x45, 0x49, 0xd6, 0x09, 0x5f, 0x6b, 0xd4, 0x8c, + 0xc9, 0x99, 0x36, 0xfb, 0x89, 0xf6, 0xa1, 0xd4, 0xd3, 0x2c, 0x5b, 0xb1, 0x06, 0xaa, 0x61, 0x75, + 0x75, 0xdb, 0xaa, 0xe4, 0xa9, 0x8e, 0x57, 0xa3, 0x74, 0xec, 0x69, 0x96, 0x7d, 0xe4, 0x30, 0x37, + 0x63, 0x72, 0xb1, 0xe7, 0x27, 0x10, 0x7d, 0xfa, 0xd9, 0x19, 0x36, 0x5d, 0x85, 0x95, 0xc2, 0x74, + 0x7d, 0x07, 0x84, 0xdb, 0x91, 0x27, 0xfa, 0x74, 0x3f, 0x01, 0x7d, 0x06, 0xcb, 0x3d, 0x5d, 0xed, + 0xb8, 0xea, 0x94, 0x76, 0x77, 0x38, 0x78, 0x5a, 0x29, 0x52, 0xa5, 0xaf, 0x47, 0x0e, 0x52, 0x57, + 0x3b, 0x8e, 0x8a, 0x3a, 0x11, 0x68, 0xc6, 0xe4, 0xa5, 0x5e, 0x98, 0x88, 0xbe, 0x80, 0x15, 0xd5, + 0x30, 0x7a, 0x97, 0x61, 0xed, 0x25, 0xaa, 0xfd, 0x5e, 0x94, 0xf6, 0x1a, 0x91, 0x09, 0xab, 0x47, + 0xea, 0x18, 0x15, 0xb5, 0x40, 0x34, 0x4c, 0x6c, 0xa8, 0x26, 0x56, 0x0c, 0x53, 0x37, 0x74, 0x4b, + 0xed, 0x55, 0xca, 0x54, 0xf7, 0x9d, 0x28, 0xdd, 0x87, 0x8c, 0xff, 0x90, 0xb3, 0x37, 0x63, 0x72, + 0xd9, 0x08, 0x92, 0x98, 0x56, 0xbd, 0x8d, 0x2d, 0xcb, 0xd3, 0x2a, 0xce, 0xd2, 0x4a, 0xf9, 0x83, + 0x5a, 0x03, 0x24, 0xd4, 0x80, 0x3c, 0x1e, 0x11, 0x71, 0xe5, 0x42, 0xb7, 0x71, 0x65, 0x89, 0x2a, + 0x94, 0x22, 0xcf, 0x19, 0x65, 0x3d, 0xd1, 0x6d, 0xdc, 0x8c, 0xc9, 0x80, 0xdd, 0x16, 0x52, 0xe1, + 0xca, 0x05, 0x36, 0xb5, 0xb3, 0x4b, 0xaa, 0x46, 0xa1, 0x3d, 0xc4, 0x1f, 0x54, 0x10, 0x55, 0xf8, + 0x46, 0x94, 0xc2, 0x13, 0x2a, 0x44, 0x54, 0x34, 0x1c, 0x91, 0x66, 0x4c, 0x5e, 0xbe, 0x18, 0x27, + 0x13, 0x13, 0x3b, 0xd3, 0x06, 0x6a, 0x4f, 0xfb, 0x1a, 0x2b, 0xd4, 0xc1, 0x55, 0x96, 0xa7, 0x9b, + 0xd8, 0x23, 0xce, 0xbd, 0x45, 0x98, 0x89, 0x89, 0x9d, 0xf9, 0x09, 0x5b, 0x19, 0x48, 0x5d, 0xa8, + 0xbd, 0x21, 0xde, 0x4d, 0x66, 0xd3, 0x62, 0x66, 0x37, 0x99, 0xcd, 0x8a, 0xb9, 0xdd, 0x64, 0x36, + 0x27, 0xc2, 0x6e, 0x32, 0x0b, 0x62, 0x5e, 0xba, 0x03, 0x79, 0x9f, 0x7b, 0x41, 0x15, 0xc8, 0xf4, + 0xb1, 0x65, 0xa9, 0xe7, 0x98, 0x7a, 0xa3, 0x9c, 0xec, 0x34, 0xa5, 0x12, 0x14, 0xfc, 0x2e, 0x45, + 0xfa, 0x4e, 0x70, 0x25, 0x89, 0xb7, 0x20, 0x92, 0xdc, 0x3d, 0x3a, 0x92, 0xbc, 0x89, 0x6e, 0x43, + 0x91, 0x4e, 0x45, 0x71, 0xfa, 0x89, 0xcb, 0x4a, 0xca, 0x05, 0x4a, 0x3c, 0xe1, 0x4c, 0x6b, 0x90, + 0x37, 0xee, 0x1b, 0x2e, 0x4b, 0x82, 0xb2, 0x80, 0x71, 0xdf, 0x70, 0x18, 0x5e, 0x81, 0x02, 0x99, + 0xb7, 0xcb, 0x91, 0xa4, 0x1f, 0xc9, 0x13, 0x1a, 0x67, 0x91, 0xfe, 0x3e, 0x01, 0x62, 0xd8, 0x0d, + 0xa1, 0xf7, 0x21, 0x49, 0x3c, 0x32, 0x77, 0xae, 0xd5, 0x0d, 0xe6, 0xae, 0x37, 0x1c, 0x77, 0xbd, + 0xd1, 0x72, 0xdc, 0xf5, 0x56, 0xf6, 0x87, 0xe7, 0x6b, 0xb1, 0xef, 0xfe, 0x77, 0x4d, 0x90, 0xa9, + 0x04, 0xba, 0x4e, 0x9c, 0x8f, 0xaa, 0x0d, 0x14, 0xad, 0x43, 0x87, 0x9c, 0x23, 0x9e, 0x45, 0xd5, + 0x06, 0x3b, 0x1d, 0xb4, 0x07, 0x62, 0x5b, 0x1f, 0x58, 0x78, 0x60, 0x0d, 0x2d, 0x85, 0x85, 0x0b, + 0xee, 0x52, 0x03, 0x8e, 0x91, 0xc5, 0x89, 0xba, 0xc3, 0x79, 0x48, 0x19, 0xe5, 0x72, 0x3b, 0x48, + 0x40, 0xfb, 0x50, 0xbc, 0x50, 0x7b, 0x5a, 0x47, 0xb5, 0x75, 0x53, 0xb1, 0xb0, 0xcd, 0x7d, 0xec, + 0xed, 0xb1, 0x3d, 0x3f, 0x71, 0xb8, 0x8e, 0xb0, 0x7d, 0x6c, 0x74, 0x54, 0x1b, 0x6f, 0x25, 0x7f, + 0x78, 0xbe, 0x26, 0xc8, 0x85, 0x0b, 0x5f, 0x0f, 0x7a, 0x0d, 0xca, 0xaa, 0x61, 0x28, 0x96, 0xad, + 0xda, 0x58, 0x39, 0xbd, 0xb4, 0xb1, 0x45, 0xdd, 0x6e, 0x41, 0x2e, 0xaa, 0x86, 0x71, 0x44, 0xa8, + 0x5b, 0x84, 0x88, 0x5e, 0x85, 0x12, 0xf1, 0xd0, 0x9a, 0xda, 0x53, 0xba, 0x58, 0x3b, 0xef, 0xda, + 0x95, 0xf4, 0xba, 0x70, 0x37, 0x21, 0x17, 0x39, 0xb5, 0x49, 0x89, 0x68, 0x03, 0x96, 0x1d, 0xb6, + 0xb6, 0x6e, 0x62, 0x87, 0x97, 0xf8, 0xe3, 0xa2, 0xbc, 0xc4, 0xbb, 0xea, 0xba, 0x89, 0x19, 0xbf, + 0xd4, 0x71, 0x2d, 0x85, 0x7a, 0x73, 0x84, 0x20, 0xd9, 0x51, 0x6d, 0x95, 0xee, 0x40, 0x41, 0xa6, + 0xbf, 0x09, 0xcd, 0x50, 0xed, 0x2e, 0x5f, 0x57, 0xfa, 0x1b, 0x5d, 0x85, 0x34, 0x57, 0x9d, 0xa0, + 0xc3, 0xe0, 0x2d, 0xb4, 0x02, 0x29, 0xc3, 0xd4, 0x2f, 0x30, 0x5d, 0x96, 0xac, 0xcc, 0x1a, 0x92, + 0x0c, 0xa5, 0xa0, 0xe7, 0x47, 0x25, 0x88, 0xdb, 0x23, 0xfe, 0x95, 0xb8, 0x3d, 0x42, 0x6f, 0x43, + 0x92, 0x6c, 0x00, 0xfd, 0x46, 0x69, 0x42, 0xac, 0xe3, 0x72, 0xad, 0x4b, 0x03, 0xcb, 0x94, 0x53, + 0xba, 0x0a, 0x2b, 0x93, 0x22, 0x81, 0xd4, 0x75, 0xe9, 0x01, 0x8f, 0x8e, 0xde, 0x85, 0xac, 0x1b, + 0x0a, 0x98, 0x7d, 0x5d, 0x1f, 0xfb, 0x8a, 0xc3, 0x2c, 0xbb, 0xac, 0xc4, 0xb0, 0xc8, 0xfe, 0x74, + 0x55, 0x1e, 0xbe, 0x0b, 0x72, 0x46, 0x35, 0x8c, 0xa6, 0x6a, 0x75, 0xa5, 0x73, 0xa8, 0x44, 0xb9, + 0x79, 0xdf, 0xfa, 0x08, 0xf4, 0x74, 0x38, 0xeb, 0xe3, 0x3b, 0x79, 0x71, 0xba, 0x27, 0xee, 0xc9, + 0xa3, 0x16, 0x3c, 0x1c, 0x3c, 0x25, 0x16, 0x9c, 0x60, 0x1f, 0xa2, 0xed, 0x9d, 0x8e, 0xd4, 0x81, + 0xeb, 0x91, 0x1e, 0x3f, 0x20, 0x27, 0x04, 0xe4, 0xc8, 0x66, 0xb0, 0x38, 0xc2, 0x06, 0xce, 0x1a, + 0x64, 0x68, 0x16, 0x9d, 0x37, 0xfd, 0x4c, 0x4e, 0xe6, 0x2d, 0xe9, 0x97, 0x24, 0x5c, 0x9d, 0xec, + 0xfc, 0xd1, 0x3a, 0x14, 0xfa, 0xea, 0x48, 0xb1, 0x47, 0xdc, 0x42, 0x05, 0xba, 0xe7, 0xd0, 0x57, + 0x47, 0xad, 0x11, 0x33, 0x4f, 0x11, 0x12, 0xf6, 0xc8, 0xaa, 0xc4, 0xd7, 0x13, 0x77, 0x0b, 0x32, + 0xf9, 0x89, 0x9e, 0xc0, 0x52, 0x4f, 0x6f, 0xab, 0x3d, 0xa5, 0xa7, 0x5a, 0xb6, 0xd2, 0xd6, 0xfb, + 0x7d, 0xcd, 0xe6, 0xe7, 0xee, 0xc6, 0xf8, 0xf6, 0xd2, 0x6e, 0xe2, 0x9b, 0xe8, 0x21, 0x89, 0xc9, + 0x65, 0x2a, 0xbb, 0xa7, 0x5a, 0x36, 0xeb, 0x42, 0xdb, 0x90, 0xef, 0x6b, 0xd6, 0x29, 0xee, 0xaa, + 0x17, 0x9a, 0x6e, 0x56, 0x92, 0xeb, 0x89, 0x89, 0x39, 0xd1, 0x13, 0x8f, 0x87, 0x6b, 0xf2, 0x8b, + 0xf9, 0xb6, 0x25, 0x15, 0x30, 0x5b, 0xc7, 0xf1, 0xa4, 0x17, 0x76, 0x3c, 0x6f, 0xc3, 0xca, 0x00, + 0x8f, 0x6c, 0xc5, 0x3d, 0xd4, 0x16, 0xb3, 0x95, 0x0c, 0x5d, 0x72, 0x44, 0xfa, 0x5c, 0x4f, 0x60, + 0x11, 0xb3, 0x21, 0xbb, 0x62, 0xea, 0xc3, 0x41, 0xa7, 0x92, 0x5d, 0x17, 0xee, 0xa6, 0x64, 0xd6, + 0x40, 0x0f, 0xa1, 0x42, 0x0f, 0x2c, 0xf3, 0x62, 0xc4, 0xdb, 0xe2, 0x8e, 0x73, 0x7a, 0x73, 0xd4, + 0x52, 0xae, 0x90, 0x7e, 0xea, 0x27, 0xf7, 0x68, 0x2f, 0x3f, 0xf1, 0x9b, 0xb0, 0xc2, 0xa2, 0x2f, + 0x36, 0x49, 0x18, 0x26, 0x9b, 0x44, 0x07, 0x00, 0x74, 0x00, 0x4b, 0x4e, 0xdf, 0xa1, 0xa9, 0xb7, + 0x46, 0xf4, 0xfb, 0x6f, 0xbb, 0x02, 0x1d, 0x85, 0x98, 0xb6, 0x63, 0x8f, 0x79, 0x6a, 0xa8, 0xc8, + 0xe9, 0xab, 0x19, 0xae, 0x3b, 0x7f, 0xe8, 0x19, 0x6d, 0x61, 0x3c, 0x25, 0xe4, 0x5d, 0x9e, 0xeb, + 0xf4, 0x6c, 0x7a, 0x0d, 0xf2, 0x5f, 0x0d, 0x75, 0x73, 0xd8, 0x67, 0x43, 0x2a, 0xd2, 0x21, 0x01, + 0x23, 0xd1, 0x23, 0xf4, 0x6f, 0x29, 0x9f, 0xcd, 0x05, 0xf3, 0x00, 0x6e, 0x51, 0x82, 0x67, 0x51, + 0x47, 0xbe, 0x81, 0xfb, 0x8d, 0x2a, 0x3e, 0xaf, 0x51, 0xb9, 0x73, 0x8b, 0xb6, 0xab, 0xc4, 0xaf, + 0xb3, 0x2b, 0x04, 0x49, 0x3a, 0xc3, 0x24, 0x73, 0x9b, 0xe4, 0x77, 0xa4, 0xad, 0xb9, 0xfb, 0x9f, + 0xf6, 0xef, 0xbf, 0x63, 0x81, 0x99, 0xdf, 0xcc, 0x02, 0xb3, 0x91, 0x16, 0xf8, 0xab, 0x6d, 0xad, + 0x05, 0x57, 0x43, 0x82, 0xca, 0x90, 0x86, 0x36, 0x6a, 0x6d, 0xa1, 0x84, 0xdf, 0x09, 0xa8, 0x3e, + 0x45, 0xf2, 0x72, 0x40, 0x2f, 0x0b, 0x8b, 0x91, 0x16, 0x9c, 0x5f, 0xd4, 0x82, 0x0b, 0xf3, 0x58, + 0x70, 0xf1, 0x65, 0x2c, 0xb8, 0x34, 0x66, 0xc1, 0xc7, 0xb0, 0x34, 0x96, 0x8a, 0xba, 0xe6, 0x20, + 0x4c, 0x34, 0x87, 0xf8, 0x64, 0x73, 0x48, 0xf8, 0xcc, 0x41, 0xfa, 0x49, 0x80, 0x6a, 0x74, 0x46, + 0x3a, 0xf1, 0x03, 0xef, 0xc0, 0x15, 0x2f, 0x33, 0xf1, 0xaf, 0x23, 0xf3, 0xfe, 0xc8, 0xed, 0xf4, + 0x16, 0x72, 0x4a, 0x14, 0x67, 0x63, 0x4a, 0xfa, 0x4d, 0xf4, 0x09, 0x94, 0x83, 0xb9, 0x34, 0x49, + 0x55, 0xc8, 0x71, 0xf9, 0xb3, 0xb1, 0xe3, 0xe2, 0xad, 0x85, 0x3b, 0x66, 0xb9, 0x74, 0xe1, 0x6f, + 0x5a, 0xd2, 0x7f, 0xc6, 0xdd, 0x48, 0x1d, 0x48, 0x8c, 0xd1, 0x07, 0x90, 0xe6, 0x27, 0x5b, 0x98, + 0xf7, 0x64, 0x73, 0x81, 0xf0, 0x69, 0x8e, 0xbf, 0xdc, 0x69, 0x4e, 0x4c, 0xdc, 0xbe, 0xe4, 0xe4, + 0xa5, 0x4a, 0xf9, 0x97, 0xea, 0x2d, 0x48, 0xb1, 0x1b, 0x01, 0x0b, 0x28, 0xd7, 0xc6, 0xcf, 0x05, + 0x9d, 0xaa, 0xcc, 0xb8, 0x50, 0x0d, 0xb2, 0x2c, 0xeb, 0xd6, 0x3a, 0xdc, 0x01, 0x5c, 0x8f, 0x90, + 0xd8, 0xd9, 0xde, 0xca, 0xbf, 0x78, 0xbe, 0x96, 0xe1, 0x0d, 0x39, 0x43, 0xe5, 0x76, 0x3a, 0xd2, + 0xbf, 0xe7, 0x20, 0x2b, 0x63, 0xcb, 0x20, 0x26, 0x8c, 0xb6, 0x20, 0x87, 0x47, 0x6d, 0x6c, 0xd8, + 0x4e, 0x86, 0x3f, 0xf9, 0x06, 0xc5, 0xb8, 0x1b, 0x0e, 0x67, 0x33, 0x26, 0x7b, 0x62, 0xe8, 0x01, + 0x07, 0x3a, 0xa2, 0x31, 0x0b, 0x2e, 0xee, 0x47, 0x3a, 0xde, 0x73, 0x90, 0x0e, 0x16, 0xe8, 0x57, + 0x23, 0xa5, 0x42, 0x50, 0xc7, 0x03, 0x0e, 0x75, 0x24, 0x67, 0x7c, 0x2c, 0x80, 0x75, 0xd4, 0x03, + 0x58, 0x47, 0x6a, 0xc6, 0x34, 0x23, 0xc0, 0x8e, 0xf7, 0x1c, 0xb0, 0x23, 0x3d, 0x63, 0xc4, 0x21, + 0xb4, 0xe3, 0x2f, 0xc7, 0xd0, 0x8e, 0xf5, 0x48, 0xd1, 0x09, 0x70, 0xc7, 0xc1, 0x18, 0xdc, 0x91, + 0xa5, 0x4a, 0x5e, 0x8b, 0x54, 0x32, 0x03, 0xef, 0x38, 0x18, 0xc3, 0x3b, 0x72, 0x33, 0x14, 0xce, + 0x00, 0x3c, 0xfe, 0x76, 0x32, 0xe0, 0x01, 0x91, 0x90, 0x04, 0x1f, 0xe6, 0x7c, 0x88, 0x87, 0x12, + 0x81, 0x78, 0xe4, 0x23, 0x6f, 0xe7, 0x4c, 0xfd, 0xdc, 0x90, 0xc7, 0xf1, 0x04, 0xc8, 0x83, 0x25, + 0x2f, 0x77, 0x23, 0x95, 0xcf, 0x81, 0x79, 0x1c, 0x4f, 0xc0, 0x3c, 0x8a, 0x33, 0xd5, 0xce, 0x04, + 0x3d, 0x1e, 0x05, 0x41, 0x8f, 0x52, 0xc4, 0x9d, 0xd2, 0x3b, 0xb2, 0x11, 0xa8, 0xc7, 0x69, 0x14, + 0xea, 0xc1, 0xd0, 0x9e, 0x37, 0x23, 0x35, 0x2e, 0x00, 0x7b, 0x1c, 0x8c, 0xc1, 0x1e, 0xe2, 0x0c, + 0x4b, 0x9b, 0x13, 0xf7, 0x90, 0x5e, 0x27, 0xb1, 0x34, 0xe4, 0x94, 0x88, 0x83, 0xc5, 0xa6, 0xa9, + 0x9b, 0x1c, 0xa9, 0x60, 0x0d, 0xe9, 0x2e, 0xb9, 0xb7, 0x7a, 0x0e, 0x68, 0x0a, 0x16, 0x52, 0x86, + 0x62, 0xc0, 0xe9, 0x48, 0xff, 0x22, 0x78, 0xb2, 0x14, 0x0d, 0xf1, 0xdf, 0x79, 0x73, 0xfc, 0xce, + 0x1b, 0xba, 0xa7, 0xe5, 0x02, 0x19, 0x81, 0x3f, 0xe7, 0xe0, 0xe0, 0x87, 0xea, 0xe5, 0x1a, 0xf7, + 0x60, 0x89, 0x66, 0xa7, 0xcc, 0xa3, 0x07, 0x82, 0x46, 0x99, 0x74, 0xb0, 0x55, 0x60, 0xd1, 0xe3, + 0x2d, 0x58, 0xf6, 0xf1, 0xba, 0x17, 0x4d, 0x86, 0x00, 0x88, 0x2e, 0x77, 0x8d, 0xdf, 0x38, 0xff, + 0x2f, 0xee, 0xad, 0x90, 0x87, 0x9a, 0x4c, 0x02, 0x38, 0x84, 0x5f, 0x0d, 0x70, 0x44, 0x5f, 0x78, + 0xd1, 0x67, 0xb0, 0x12, 0xc0, 0x3e, 0x9c, 0xe4, 0x2f, 0xb1, 0x18, 0x04, 0x12, 0xf3, 0xe5, 0x22, + 0x6e, 0x0f, 0xfa, 0x1c, 0x6e, 0xd0, 0x34, 0x36, 0x22, 0xc1, 0x4c, 0xce, 0x97, 0x60, 0x5e, 0x23, + 0x3a, 0xea, 0x13, 0x92, 0xcc, 0x08, 0x60, 0x24, 0x15, 0x05, 0x8c, 0xfc, 0x4e, 0xf0, 0xec, 0xc6, + 0x85, 0x46, 0xda, 0x7a, 0x87, 0xd9, 0x57, 0x51, 0xa6, 0xbf, 0xc9, 0x25, 0xa5, 0xa7, 0x9f, 0x73, + 0x13, 0x21, 0x3f, 0x09, 0x97, 0x0b, 0xda, 0xe7, 0x78, 0xa0, 0x5a, 0x81, 0x94, 0x36, 0xe8, 0xe0, + 0x11, 0xb7, 0x02, 0xd6, 0x20, 0xb2, 0x4f, 0xf1, 0x25, 0xdf, 0x6b, 0xf2, 0x93, 0xf0, 0xd1, 0x83, + 0x40, 0x63, 0x51, 0x41, 0x66, 0x0d, 0xf4, 0x3e, 0xe4, 0x68, 0xe5, 0x45, 0xd1, 0x0d, 0x8b, 0x87, + 0x9a, 0x40, 0x46, 0xc4, 0xaa, 0x24, 0x1b, 0x87, 0x84, 0xe7, 0xc0, 0xb0, 0xe4, 0xac, 0xc1, 0x7f, + 0xf9, 0x72, 0x96, 0x6c, 0x20, 0x67, 0xb9, 0x09, 0x39, 0x32, 0x7a, 0xcb, 0x50, 0xdb, 0x98, 0x86, + 0x89, 0x9c, 0xec, 0x11, 0xa4, 0x7f, 0x15, 0xa0, 0x1c, 0x8a, 0x5c, 0x13, 0xe7, 0xee, 0x1c, 0x9b, + 0x78, 0x10, 0x2a, 0x1a, 0x9b, 0xfd, 0x2d, 0x80, 0x73, 0xd5, 0x52, 0x9e, 0xa9, 0x03, 0x1b, 0x77, + 0xf8, 0x12, 0xe4, 0xce, 0x55, 0xeb, 0x13, 0x4a, 0x08, 0x0e, 0x26, 0x15, 0x1a, 0x8c, 0x0f, 0xac, + 0x48, 0xfb, 0xc1, 0x0a, 0x54, 0x85, 0xac, 0x61, 0x6a, 0xba, 0xa9, 0xd9, 0x97, 0x74, 0x4d, 0x12, + 0xb2, 0xdb, 0x96, 0x0e, 0xe1, 0xca, 0xc4, 0xa0, 0x89, 0x1e, 0x42, 0xce, 0x8b, 0xb7, 0x02, 0xcd, + 0x0d, 0xa7, 0x60, 0x40, 0x1e, 0x2f, 0x59, 0x92, 0x2b, 0x13, 0xc3, 0x26, 0x6a, 0x40, 0xda, 0xc4, + 0xd6, 0xb0, 0xc7, 0x72, 0xd5, 0xd2, 0xfd, 0xb7, 0xe6, 0x0b, 0xb7, 0x84, 0x3a, 0xec, 0xd9, 0x32, + 0x17, 0x96, 0xbe, 0x80, 0x34, 0xa3, 0xa0, 0x3c, 0x64, 0x8e, 0xf7, 0x1f, 0xef, 0x1f, 0x7c, 0xb2, + 0x2f, 0xc6, 0x10, 0x40, 0xba, 0x56, 0xaf, 0x37, 0x0e, 0x5b, 0xa2, 0x80, 0x72, 0x90, 0xaa, 0x6d, + 0x1d, 0xc8, 0x2d, 0x31, 0x4e, 0xc8, 0x72, 0x63, 0xb7, 0x51, 0x6f, 0x89, 0x09, 0xb4, 0x04, 0x45, + 0xf6, 0x5b, 0x79, 0x74, 0x20, 0x3f, 0xa9, 0xb5, 0xc4, 0xa4, 0x8f, 0x74, 0xd4, 0xd8, 0xdf, 0x6e, + 0xc8, 0x62, 0x4a, 0x7a, 0x07, 0xae, 0x47, 0x06, 0x68, 0x0f, 0x26, 0x12, 0x7c, 0x30, 0x91, 0xf4, + 0x63, 0x9c, 0xdc, 0x40, 0xa2, 0xa2, 0x2e, 0xda, 0x0d, 0x4d, 0xfc, 0xfe, 0x02, 0x21, 0x3b, 0x34, + 0x7b, 0xf4, 0x2a, 0x94, 0x4c, 0x7c, 0x86, 0xed, 0x76, 0x97, 0x65, 0x01, 0x0e, 0x8e, 0x54, 0xe4, + 0x54, 0x2a, 0x64, 0x31, 0xb6, 0x2f, 0x71, 0xdb, 0x56, 0x98, 0x11, 0x58, 0xf4, 0xb6, 0x9e, 0x23, + 0x6c, 0x84, 0x7a, 0xc4, 0x88, 0xc4, 0x41, 0x33, 0x47, 0xc2, 0x54, 0x25, 0xa9, 0x2a, 0xa0, 0x7e, + 0x81, 0x52, 0xa4, 0x67, 0x0b, 0x2d, 0x76, 0x0e, 0x52, 0x72, 0xa3, 0x25, 0x7f, 0x2a, 0x26, 0x10, + 0x82, 0x12, 0xfd, 0xa9, 0x1c, 0xed, 0xd7, 0x0e, 0x8f, 0x9a, 0x07, 0x64, 0xb1, 0x97, 0xa1, 0xec, + 0x2c, 0xb6, 0x43, 0x4c, 0xa1, 0x2b, 0xb0, 0x54, 0x3f, 0x78, 0x72, 0xb8, 0xd7, 0x68, 0x35, 0x3c, + 0x72, 0x5a, 0xfa, 0xef, 0x04, 0x5c, 0x8b, 0xc8, 0x35, 0xd0, 0xfb, 0x00, 0xf6, 0x48, 0x31, 0x71, + 0x5b, 0x37, 0x3b, 0xd1, 0xc6, 0xd9, 0x1a, 0xc9, 0x94, 0x43, 0xce, 0xd9, 0xfc, 0xd7, 0x54, 0x87, + 0xfd, 0x11, 0x57, 0x4a, 0x26, 0x6b, 0x71, 0x6c, 0xe3, 0xd6, 0x84, 0xcb, 0x1a, 0x6e, 0x13, 0xc5, + 0x74, 0x4f, 0xa8, 0x62, 0xca, 0x8f, 0x3e, 0x85, 0x6b, 0xa1, 0xb8, 0xc2, 0x9d, 0xb1, 0x35, 0xa9, + 0xb0, 0x38, 0x39, 0xbc, 0x5c, 0x09, 0x86, 0x17, 0xe6, 0x8c, 0xad, 0x29, 0x40, 0x42, 0xea, 0x25, + 0x80, 0x84, 0xa8, 0xf8, 0x94, 0x5e, 0x14, 0xa2, 0x9f, 0x14, 0x9f, 0x42, 0x71, 0x3f, 0x13, 0x8e, + 0xfb, 0xd2, 0xef, 0x03, 0xbb, 0x1b, 0xcc, 0xef, 0x0e, 0x20, 0x6d, 0xd9, 0xaa, 0x3d, 0xb4, 0xf8, + 0x69, 0x79, 0x38, 0x6f, 0xb2, 0xb8, 0xe1, 0xfc, 0x38, 0xa2, 0xe2, 0x32, 0x57, 0xf3, 0x27, 0xb9, + 0xe9, 0x51, 0xdb, 0x93, 0xfa, 0x2d, 0xb6, 0xa7, 0x09, 0x69, 0x7c, 0x81, 0x07, 0xb6, 0x55, 0x49, + 0xd3, 0x19, 0x5f, 0x1d, 0x9f, 0x31, 0xe9, 0xde, 0xaa, 0x90, 0x04, 0xe4, 0xff, 0x9f, 0xaf, 0x89, + 0x8c, 0xfb, 0x4d, 0xbd, 0xaf, 0xd9, 0xb8, 0x6f, 0xd8, 0x97, 0x32, 0x97, 0x97, 0xde, 0x85, 0x52, + 0x70, 0xd1, 0xa3, 0xdd, 0x84, 0xe7, 0x88, 0xe3, 0xd2, 0x3f, 0x0b, 0xb0, 0x3c, 0x01, 0xf6, 0x40, + 0x0f, 0x79, 0x65, 0x83, 0x6d, 0xfc, 0xed, 0xf1, 0xd5, 0x0b, 0xb0, 0x7b, 0x05, 0x0e, 0x12, 0x18, + 0xbd, 0xfc, 0x9d, 0xed, 0xb1, 0x47, 0x40, 0x6f, 0x40, 0xd9, 0xd2, 0xce, 0x07, 0x8a, 0xc9, 0x10, + 0x14, 0xb7, 0x6a, 0x40, 0xd2, 0x6b, 0xd2, 0xe1, 0xd4, 0xd6, 0x3a, 0xff, 0x20, 0x08, 0x5b, 0x08, + 0x44, 0x25, 0xc4, 0x2d, 0xb5, 0x01, 0x8d, 0x5f, 0x27, 0x26, 0x61, 0x3c, 0xc2, 0x4b, 0x60, 0x3c, + 0xff, 0x24, 0xc0, 0x8d, 0x29, 0x57, 0x0c, 0xf4, 0x71, 0xe8, 0x5c, 0x7c, 0xb0, 0xc8, 0x05, 0x65, + 0x83, 0xd1, 0x82, 0x27, 0x43, 0x7a, 0x00, 0x05, 0x3f, 0x7d, 0xbe, 0xcd, 0xdb, 0xf5, 0xe2, 0x7b, + 0x10, 0x8b, 0xba, 0x0d, 0x45, 0x13, 0xdb, 0xc4, 0x49, 0x05, 0xc0, 0xbb, 0x02, 0x23, 0xb2, 0x5c, + 0x71, 0x37, 0x99, 0x15, 0xc4, 0xb8, 0x6b, 0x3f, 0xff, 0x21, 0x00, 0x78, 0x00, 0x95, 0x07, 0x10, + 0x09, 0x7e, 0x80, 0x28, 0x84, 0x2b, 0xc6, 0xc3, 0xb8, 0x22, 0xba, 0x03, 0x65, 0x76, 0x29, 0x20, + 0xfb, 0xa6, 0xda, 0x43, 0x13, 0x73, 0x38, 0xaa, 0x44, 0xc9, 0x47, 0x0e, 0x15, 0x7d, 0x06, 0xd7, + 0xed, 0xae, 0x89, 0xad, 0xae, 0xde, 0xeb, 0x28, 0xe1, 0xbd, 0x63, 0x65, 0x92, 0xb5, 0x19, 0x46, + 0x27, 0x5f, 0x73, 0x35, 0x9c, 0x04, 0xf7, 0xef, 0x6b, 0x48, 0xd1, 0x63, 0x43, 0x12, 0x3b, 0xd7, + 0x8a, 0x73, 0xdc, 0x40, 0x3f, 0x07, 0x50, 0x6d, 0xdb, 0xd4, 0x4e, 0x87, 0xc4, 0x3b, 0xc4, 0xc7, + 0x3f, 0xe5, 0x1d, 0xbb, 0x9a, 0xc3, 0xb7, 0x75, 0x93, 0x9f, 0xbf, 0x15, 0x4f, 0xd4, 0x77, 0x06, + 0x7d, 0x0a, 0xa5, 0x7d, 0x28, 0x05, 0x65, 0x9d, 0x8c, 0x99, 0x8d, 0x21, 0x98, 0x31, 0xb3, 0x0c, + 0x9c, 0x67, 0xcc, 0x6e, 0xbe, 0x9d, 0x60, 0x45, 0x48, 0xda, 0x90, 0x7e, 0x11, 0xa0, 0xe0, 0xf7, + 0x7a, 0x73, 0x27, 0xb5, 0x3c, 0xc9, 0x4f, 0x8c, 0x27, 0xf9, 0x49, 0x5f, 0x9a, 0x7b, 0x1d, 0xb2, + 0x24, 0xcd, 0x1d, 0x5a, 0xb8, 0xc3, 0x4b, 0xb3, 0x99, 0x73, 0xd5, 0x3a, 0xb6, 0x70, 0xc7, 0xe7, + 0x9b, 0x32, 0x2f, 0xe7, 0x9b, 0x82, 0xc9, 0x72, 0x36, 0x94, 0x2c, 0xef, 0x26, 0xb3, 0x29, 0x31, + 0x2d, 0xfb, 0xb2, 0x6d, 0xe9, 0x1b, 0x01, 0xb2, 0xee, 0x7c, 0x83, 0x35, 0xc9, 0x00, 0x84, 0xc9, + 0x96, 0x8b, 0x55, 0x24, 0xf9, 0xf5, 0x84, 0x55, 0x68, 0x13, 0x6e, 0x85, 0xf6, 0x43, 0x37, 0xe1, + 0x8b, 0x02, 0xe9, 0xfc, 0x8b, 0xeb, 0xe0, 0xb2, 0x3c, 0xbf, 0xfd, 0x47, 0x3e, 0x0e, 0x92, 0xb1, + 0xa0, 0xbf, 0x80, 0xb4, 0xda, 0x76, 0xa1, 0xc9, 0xd2, 0x04, 0xcc, 0xce, 0x61, 0xdd, 0x68, 0x8d, + 0x6a, 0x94, 0x53, 0xe6, 0x12, 0x7c, 0x54, 0x71, 0x67, 0x54, 0xd2, 0x1e, 0xd1, 0xcb, 0x78, 0x82, + 0x27, 0xbd, 0x04, 0x70, 0xbc, 0xff, 0xe4, 0x60, 0x7b, 0xe7, 0xd1, 0x4e, 0x63, 0x9b, 0x67, 0x74, + 0xdb, 0xdb, 0x8d, 0x6d, 0x31, 0x4e, 0xf8, 0xe4, 0xc6, 0x93, 0x83, 0x93, 0xc6, 0xb6, 0x98, 0x20, + 0x8d, 0xed, 0xc6, 0x5e, 0xed, 0xd3, 0xc6, 0xb6, 0x98, 0x94, 0x6a, 0x90, 0x73, 0x83, 0x0e, 0x2d, + 0x65, 0xeb, 0xcf, 0xb0, 0xc9, 0x57, 0x8b, 0x35, 0xd0, 0x2a, 0xe4, 0xc7, 0xb1, 0x75, 0x72, 0x41, + 0x63, 0x90, 0x3a, 0x09, 0x03, 0x65, 0x57, 0x07, 0x8f, 0x4d, 0x1f, 0x42, 0xc6, 0x18, 0x9e, 0x2a, + 0x8e, 0xed, 0x86, 0x10, 0x69, 0xe7, 0xfe, 0x36, 0x3c, 0xed, 0x69, 0xed, 0xc7, 0xf8, 0x92, 0x07, + 0xb9, 0xb4, 0x31, 0x3c, 0x7d, 0xcc, 0x4c, 0x9c, 0x0d, 0x23, 0x3e, 0x65, 0x18, 0x89, 0xd0, 0x30, + 0xd0, 0x1d, 0x28, 0x0c, 0xf4, 0x0e, 0x56, 0xd4, 0x4e, 0xc7, 0xc4, 0x16, 0x8b, 0xdd, 0x39, 0xae, + 0x39, 0x4f, 0x7a, 0x6a, 0xac, 0x43, 0xfa, 0x49, 0x00, 0x34, 0x1e, 0x68, 0xd1, 0x11, 0x2c, 0x79, + 0xb1, 0xda, 0x49, 0x00, 0x58, 0x24, 0x58, 0x8f, 0x0e, 0xd4, 0x81, 0x4b, 0xbe, 0x78, 0x11, 0x24, + 0x93, 0xac, 0x6f, 0xc5, 0x73, 0x55, 0x06, 0x9d, 0x2f, 0x5d, 0x94, 0xf8, 0x9c, 0x8b, 0x12, 0x93, + 0x91, 0x2b, 0xef, 0xf6, 0x84, 0x5d, 0x69, 0x62, 0xac, 0x44, 0x63, 0x40, 0xa5, 0x35, 0x26, 0xc6, + 0xe7, 0x19, 0x35, 0x24, 0xe1, 0x65, 0x86, 0x24, 0x3d, 0x00, 0xf1, 0x63, 0xf7, 0xfb, 0x5e, 0xfe, + 0xe8, 0x1f, 0xa6, 0x30, 0x36, 0xcc, 0x0b, 0xc8, 0x12, 0xef, 0x4b, 0x83, 0xc6, 0x5f, 0x41, 0xce, + 0x5d, 0x3d, 0xf7, 0x35, 0x4c, 0xe4, 0xb2, 0xf3, 0x91, 0x78, 0x22, 0xe8, 0x1e, 0x2c, 0x91, 0xb8, + 0xe1, 0x14, 0x4a, 0x19, 0x4c, 0x17, 0xa7, 0xde, 0xb0, 0xcc, 0x3a, 0xf6, 0x1c, 0x6c, 0x89, 0xc4, + 0x68, 0x91, 0xc5, 0x72, 0xdc, 0xf9, 0x63, 0x0c, 0x80, 0xdc, 0xeb, 0x42, 0x68, 0x25, 0xdb, 0xc3, + 0x62, 0x20, 0x99, 0x90, 0xfe, 0x2e, 0x0e, 0x79, 0x5f, 0xe1, 0x06, 0xfd, 0x79, 0x20, 0xb1, 0x5a, + 0x9f, 0x56, 0xe4, 0xf1, 0x65, 0x55, 0x81, 0x89, 0xc5, 0x17, 0x9f, 0x58, 0x54, 0xc9, 0xcc, 0xa9, + 0xdf, 0x26, 0x17, 0xae, 0xdf, 0xbe, 0x09, 0xc8, 0xd6, 0x6d, 0xb5, 0x47, 0x82, 0xb7, 0x36, 0x38, + 0x57, 0xd8, 0x69, 0x67, 0x35, 0x63, 0x91, 0xf6, 0x9c, 0xd0, 0x8e, 0x43, 0x42, 0x97, 0x7a, 0x90, + 0x75, 0xc1, 0x87, 0xc5, 0x1f, 0x99, 0x4c, 0xaa, 0x53, 0x57, 0x21, 0xdb, 0xc7, 0xb6, 0x4a, 0xc3, + 0x1e, 0x03, 0xa3, 0xdc, 0xf6, 0xbd, 0x0f, 0x20, 0xef, 0x7b, 0x79, 0x43, 0x22, 0xe1, 0x7e, 0xe3, + 0x13, 0x31, 0x56, 0xcd, 0x7c, 0xfb, 0xfd, 0x7a, 0x62, 0x1f, 0x3f, 0x23, 0x9f, 0x92, 0x1b, 0xf5, + 0x66, 0xa3, 0xfe, 0x58, 0x14, 0xaa, 0xf9, 0x6f, 0xbf, 0x5f, 0xcf, 0xc8, 0x98, 0xd6, 0x38, 0xee, + 0x3d, 0x86, 0x72, 0x68, 0x07, 0x82, 0x0e, 0x1a, 0x41, 0x69, 0xfb, 0xf8, 0x70, 0x6f, 0xa7, 0x5e, + 0x6b, 0x35, 0x94, 0x93, 0x83, 0x56, 0x43, 0x14, 0xd0, 0x35, 0x58, 0xde, 0xdb, 0xf9, 0xeb, 0x66, + 0x4b, 0xa9, 0xef, 0xed, 0x34, 0xf6, 0x5b, 0x4a, 0xad, 0xd5, 0xaa, 0xd5, 0x1f, 0x8b, 0xf1, 0xfb, + 0xff, 0x03, 0x50, 0xae, 0x6d, 0xd5, 0x77, 0x6a, 0x86, 0xd1, 0xd3, 0xda, 0x2a, 0x75, 0xf7, 0x75, + 0x48, 0x52, 0xe8, 0x77, 0xea, 0x1b, 0xdc, 0xea, 0xf4, 0xc2, 0x15, 0x7a, 0x04, 0x29, 0x8a, 0x0a, + 0xa3, 0xe9, 0x8f, 0x72, 0xab, 0x33, 0x2a, 0x59, 0x64, 0x30, 0xf4, 0xdc, 0x4c, 0x7d, 0xa5, 0x5b, + 0x9d, 0x5e, 0xd8, 0x42, 0x7b, 0x90, 0x71, 0x00, 0xb7, 0x59, 0x4f, 0x67, 0xab, 0x33, 0xab, 0x4d, + 0x64, 0x6a, 0x0c, 0xb8, 0x9c, 0xfe, 0x80, 0xb7, 0x3a, 0xa3, 0xe4, 0x85, 0x64, 0xc8, 0x79, 0x58, + 0xf3, 0xec, 0xb7, 0xc4, 0xd5, 0x39, 0x4a, 0x70, 0xe8, 0x0b, 0x28, 0x06, 0xa1, 0xb9, 0xf9, 0x9e, + 0xf9, 0x56, 0xe7, 0x2c, 0x8f, 0x11, 0xfd, 0x41, 0x9c, 0x6e, 0xbe, 0x67, 0xbf, 0xd5, 0x39, 0xab, + 0x65, 0xe8, 0x4b, 0x58, 0x1a, 0xc7, 0xd1, 0xe6, 0x7f, 0x05, 0x5c, 0x5d, 0xa0, 0x7e, 0x86, 0xfa, + 0x80, 0x26, 0xe0, 0x6f, 0x0b, 0x3c, 0x0a, 0xae, 0x2e, 0x52, 0x4e, 0x43, 0x1d, 0x28, 0x87, 0xb1, + 0xa9, 0x79, 0x1f, 0x09, 0x57, 0xe7, 0x2e, 0xad, 0xb1, 0xaf, 0x04, 0x31, 0x92, 0x79, 0x1f, 0x0d, + 0x57, 0xe7, 0xae, 0xb4, 0xa1, 0x63, 0x00, 0xdf, 0xdd, 0x76, 0x8e, 0x47, 0xc4, 0xd5, 0x79, 0x6a, + 0x6e, 0xc8, 0x80, 0xe5, 0x49, 0x97, 0xd9, 0x45, 0xde, 0x14, 0x57, 0x17, 0x2a, 0xc5, 0x11, 0x7b, + 0x0e, 0xde, 0x4b, 0xe7, 0x7b, 0x63, 0x5c, 0x9d, 0xb3, 0x26, 0xb7, 0xb5, 0xf5, 0xc3, 0x8b, 0x55, + 0xe1, 0xc7, 0x17, 0xab, 0xc2, 0x4f, 0x2f, 0x56, 0x85, 0xef, 0x7e, 0x5e, 0x8d, 0xfd, 0xf8, 0xf3, + 0x6a, 0xec, 0xbf, 0x7e, 0x5e, 0x8d, 0xfd, 0xcd, 0xdd, 0x73, 0xcd, 0xee, 0x0e, 0x4f, 0x37, 0xda, + 0x7a, 0x9f, 0xfe, 0xc5, 0xc3, 0x50, 0x2f, 0x37, 0x99, 0x4e, 0xd2, 0xf2, 0xfd, 0x91, 0xe4, 0x34, + 0x4d, 0x63, 0xdd, 0x83, 0x3f, 0x04, 0x00, 0x00, 0xff, 0xff, 0xf2, 0x22, 0x4b, 0xdf, 0x68, 0x32, + 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -7242,6 +7254,11 @@ func (m *ResponsePrepareProposal) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if m.AppVersion != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.AppVersion)) + i-- + dAtA[i] = 0x38 + } if m.ValidatorSetUpdate != nil { { size, err := m.ValidatorSetUpdate.MarshalToSizedBuffer(dAtA[:i]) @@ -9323,6 +9340,9 @@ func (m *ResponsePrepareProposal) Size() (n int) { l = m.ValidatorSetUpdate.Size() n += 1 + l + sovTypes(uint64(l)) } + if m.AppVersion != 0 { + n += 1 + sovTypes(uint64(m.AppVersion)) + } return n } @@ -15414,6 +15434,25 @@ func (m *ResponsePrepareProposal) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 7: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field AppVersion", wireType) + } + m.AppVersion = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTypes + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.AppVersion |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) diff --git a/dash/quorum/validator_conn_executor_test.go b/dash/quorum/validator_conn_executor_test.go index a54bf180c4..8ea0bc2591 100644 --- a/dash/quorum/validator_conn_executor_test.go +++ b/dash/quorum/validator_conn_executor_test.go @@ -658,8 +658,9 @@ func (app *testApp) PrepareProposal(_ context.Context, req *abci.RequestPrepareP } return &abci.ResponsePrepareProposal{ - AppHash: resultsHash, - TxResults: results, + AppHash: resultsHash, + TxResults: results, + AppVersion: 1, }, nil } diff --git a/internal/consensus/common_test.go b/internal/consensus/common_test.go index 5a55a4fe50..a3de1f11cd 100644 --- a/internal/consensus/common_test.go +++ b/internal/consensus/common_test.go @@ -876,7 +876,7 @@ func makeConsensusState( walDir := filepath.Dir(thisConfig.Consensus.WalFile()) ensureDir(t, walDir, 0700) - app, err := kvstore.NewMemoryApp() + app, err := kvstore.NewMemoryApp(kvstore.WithLogger(logger)) require.NoError(t, err) t.Cleanup(func() { _ = app.Close() }) diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index 6d5712da17..1e71ec3bff 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -349,9 +349,10 @@ func (app *CounterApplication) PrepareProposal(_ context.Context, req *abci.Requ }) } return &abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), - TxRecords: trs, - TxResults: app.txResults(req.Txs), + AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: app.txResults(req.Txs), + AppVersion: 1, }, nil } diff --git a/internal/consensus/state_test.go b/internal/consensus/state_test.go index 4b2d5d8c5b..de01f96a6c 100644 --- a/internal/consensus/state_test.go +++ b/internal/consensus/state_test.go @@ -2025,7 +2025,7 @@ func TestProcessProposalAccept(t *testing.T) { Status: status, }, nil) m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil).Maybe() cs1, _ := makeState(ctx, t, makeStateArgs{config: config, application: m}) @@ -2080,7 +2080,7 @@ func TestFinalizeBlockCalled(t *testing.T) { Status: abci.ResponseProcessProposal_ACCEPT, }, nil) m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil) // We only expect VerifyVoteExtension to be called on non-nil precommits. // https://github.com/tendermint/tendermint/issues/8487 @@ -2152,7 +2152,7 @@ func TestExtendVote(t *testing.T) { Status: abci.ResponseProcessProposal_ACCEPT, }, nil) m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil) m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ VoteExtensions: []*abci.ExtendVoteExtension{ @@ -2311,7 +2311,7 @@ func TestVerifyVoteExtensionNotCalledOnAbsentPrecommit(t *testing.T) { Status: abci.ResponseProcessProposal_ACCEPT, }, nil) m.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil) m.On("ExtendVote", mock.Anything, mock.Anything).Return(&abci.ResponseExtendVote{ VoteExtensions: voteExtensions.ToExtendProto(), @@ -2434,7 +2434,7 @@ func TestPrepareProposalReceivesVoteExtensions(t *testing.T) { assert.EqualValues(t, voteExtensions.GetExtensions(), extensions) })).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil) m.On("VerifyVoteExtension", mock.Anything, mock.Anything).Return(&abci.ResponseVerifyVoteExtension{Status: abci.ResponseVerifyVoteExtension_ACCEPT}, nil) @@ -3157,6 +3157,7 @@ func TestStateTryAddCommitCallsProcessProposal(t *testing.T) { block, err := sf.MakeBlock(css0StateData.state, 1, &types.Commit{}, kvstore.ProtocolVersion) require.NoError(t, err) + require.NotZero(t, block.Version.App) block.CoreChainLockedHeight = 1 commit, err := factory.MakeCommit( @@ -3322,7 +3323,7 @@ func mockProposerApplicationCalls(t *testing.T, m *abcimocks.Application, round }) m.On("PrepareProposal", mock.Anything, roundMatcher).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil).Once() m.On("ProcessProposal", mock.Anything, roundMatcher).Return(&abci.ResponseProcessProposal{ diff --git a/internal/state/execution.go b/internal/state/execution.go index 1e03339454..c9fd2073a8 100644 --- a/internal/state/execution.go +++ b/internal/state/execution.go @@ -233,7 +233,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock( QuorumHash: state.Validators.QuorumHash, } start := time.Now() - rpp, err := blockExec.appClient.PrepareProposal(ctx, &request) + response, err := blockExec.appClient.PrepareProposal(ctx, &request) if err != nil { // The App MUST ensure that only valid (and hence 'processable') transactions // enter the mempool. Hence, at this point, we can't have any non-processable @@ -247,7 +247,7 @@ func (blockExec *BlockExecutor) CreateProposalBlock( } // ensure that the proposal response is deterministic - reqHash, respHash := deterministicPrepareProposalHashes(&request, rpp) + reqHash, respHash := deterministicPrepareProposalHashes(&request, response) blockExec.logger.Debug("PrepareProposal executed", "request_hash", hex.EncodeToString(reqHash), "response_hash", hex.EncodeToString(respHash), @@ -266,11 +266,11 @@ func (blockExec *BlockExecutor) CreateProposalBlock( ) } - if err := rpp.Validate(); err != nil { + if err := response.Validate(); err != nil { return nil, CurrentRoundState{}, fmt.Errorf("PrepareProposal responded with invalid response: %w", err) } - txrSet := types.NewTxRecordSet(rpp.TxRecords) + txrSet := types.NewTxRecordSet(response.TxRecords) if err := txrSet.Validate(maxDataBytes, block.Txs); err != nil { return nil, CurrentRoundState{}, err @@ -283,13 +283,17 @@ func (blockExec *BlockExecutor) CreateProposalBlock( } itxs := txrSet.IncludedTxs() - if err := validateExecTxResults(rpp.TxResults, itxs); err != nil { + if err := validateExecTxResults(response.TxResults, itxs); err != nil { return nil, CurrentRoundState{}, fmt.Errorf("invalid tx results: %w", err) } block.SetTxs(itxs) - rp, err := RoundParamsFromPrepareProposal(rpp, round) + if ver := response.GetAppVersion(); ver > 0 { + block.Version.App = ver + } + + rp, err := RoundParamsFromPrepareProposal(response, round) if err != nil { return nil, CurrentRoundState{}, err } @@ -356,12 +360,12 @@ func (blockExec *BlockExecutor) ProcessProposal( if resp.IsStatusUnknown() { return CurrentRoundState{}, fmt.Errorf("ProcessProposal responded with status %s", resp.Status.String()) } - if err := resp.Validate(); err != nil { - return CurrentRoundState{}, fmt.Errorf("ProcessProposal responded with invalid response: %w", err) - } if !resp.IsAccepted() { return CurrentRoundState{}, ErrBlockRejected } + if err := resp.Validate(); err != nil { + return CurrentRoundState{}, fmt.Errorf("ProcessProposal responded with invalid response: %w", err) + } if err := validateExecTxResults(resp.TxResults, block.Data.Txs); err != nil { return CurrentRoundState{}, fmt.Errorf("invalid tx results: %w", err) } diff --git a/internal/state/execution_test.go b/internal/state/execution_test.go index fe890f927f..deeca658b2 100644 --- a/internal/state/execution_test.go +++ b/internal/state/execution_test.go @@ -88,7 +88,7 @@ func TestApplyBlock(t *testing.T) { consensusParamsBefore := state.ConsensusParams validatorsBefore := state.Validators.Hash() - block, err := sf.MakeBlock(state, 1, new(types.Commit), 1) + block, err := sf.MakeBlock(state, 1, new(types.Commit), 2) require.NoError(t, err) bps, err := block.MakePartSet(testPartSize) require.NoError(t, err) @@ -100,8 +100,8 @@ func TestApplyBlock(t *testing.T) { // State for next block // nextState, err := state.NewStateChangeset(ctx, nil) // require.NoError(t, err) - assert.EqualValues(t, 0, block.Version.App, "App version should not change in current block") - assert.EqualValues(t, 1, block.ProposedAppVersion, "Block should propose new version") + assert.EqualValues(t, 1, block.Version.App, "App version should not change in current block") + assert.EqualValues(t, 2, block.ProposedAppVersion, "Block should propose new version") assert.Equal(t, consensusParamsBefore.HashConsensusParams(), block.ConsensusHash, "consensus params should change in next block") assert.Equal(t, validatorsBefore, block.ValidatorsHash, "validators should change from the next block") @@ -324,6 +324,7 @@ func TestUpdateConsensusParams(t *testing.T) { AppHash: rand.Bytes(crypto.DefaultAppHashSize), TxResults: txResults, ConsensusParamUpdates: &tmtypes.ConsensusParams{Block: &tmtypes.BlockParams{MaxBytes: 1024 * 1024}}, + AppVersion: 1, }, nil).Once() block1, _, err := blockExec.CreateProposalBlock( ctx, @@ -350,6 +351,81 @@ func TestUpdateConsensusParams(t *testing.T) { app.AssertCalled(t, "ProcessProposal", mock.Anything, mock.Anything) } +// TestOverrideAppVersion ensures that app_version set in PrepareProposal overrides the one in the block +// and is passed to ProcessProposal. +func TestOverrideAppVersion(t *testing.T) { + const ( + height = 1 + round = int32(12) + appVersion = uint64(12345) + ) + txs := factory.MakeNTxs(height, 10) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + app := abcimocks.NewApplication(t) + logger := log.NewNopLogger() + cc := abciclient.NewLocalClient(logger, app) + proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) + err := proxyApp.Start(ctx) + require.NoError(t, err) + + state, stateDB, _ := makeState(t, 1, height) + stateStore := sm.NewStore(stateDB) + blockStore := store.NewBlockStore(dbm.NewMemDB()) + + eventBus := eventbus.NewDefault(logger) + require.NoError(t, eventBus.Start(ctx)) + + pool := new(mpmocks.Mempool) + pool.On("ReapMaxBytesMaxGas", mock.Anything, mock.Anything).Return(txs).Once() + + blockExec := sm.NewBlockExecutor( + stateStore, + proxyApp, + pool, + sm.EmptyEvidencePool{}, + blockStore, + eventBus, + ) + + lastCommit := types.NewCommit(height-1, 0, types.BlockID{}, nil, nil) + txResults := factory.ExecTxResults(txs) + + app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ + TxRecords: txsToTxRecords(txs), + AppHash: rand.Bytes(crypto.DefaultAppHashSize), + TxResults: txResults, + AppVersion: appVersion, + }, nil).Once() + + block1, _, err := blockExec.CreateProposalBlock( + ctx, + height, + round, + state, + lastCommit, + state.Validators.GetProposer().ProTxHash, + 1, + ) + require.NoError(t, err) + + app.On("ProcessProposal", mock.Anything, + mock.MatchedBy(func(r *abci.RequestProcessProposal) bool { + return r.Version.App == appVersion + })).Return(&abci.ResponseProcessProposal{ + AppHash: block1.AppHash, + TxResults: txResults, + Status: abci.ResponseProcessProposal_ACCEPT, + }, nil).Once() + + _, err = blockExec.ProcessProposal(ctx, block1, round, state, true) + require.NoError(t, err) + assert.EqualValues(t, appVersion, block1.Version.App, "App version should be overridden by PrepareProposal") + + app.AssertExpectations(t) +} + func TestValidateValidatorUpdates(t *testing.T) { pubkey1 := bls12381.GenPrivKey().PubKey() pubkey2 := bls12381.GenPrivKey().PubKey() @@ -715,7 +791,7 @@ func TestEmptyPrepareProposal(t *testing.T) { }) app.On("PrepareProposal", mock.Anything, reqPrepProposalMatch).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), + AppHash: make([]byte, crypto.DefaultAppHashSize), AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) proxyApp := proxy.New(cc, logger, proxy.NopMetrics()) @@ -783,8 +859,9 @@ func TestPrepareProposalErrorOnNonExistingRemoved(t *testing.T) { Tx: []byte("new tx"), }, }, - TxResults: []*abci.ExecTxResult{{}}, - AppHash: make([]byte, crypto.DefaultAppHashSize), + TxResults: []*abci.ExecTxResult{{}}, + AppHash: make([]byte, crypto.DefaultAppHashSize), + AppVersion: 1, } app.On("PrepareProposal", mock.Anything, mock.Anything).Return(rpp, nil) @@ -841,9 +918,10 @@ func TestPrepareProposalRemoveTxs(t *testing.T) { app := abcimocks.NewApplication(t) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - TxRecords: trs, - TxResults: txResults, - AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: txResults, + AppHash: make([]byte, crypto.DefaultAppHashSize), + AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) @@ -903,9 +981,10 @@ func TestPrepareProposalDelayedTxs(t *testing.T) { app := abcimocks.NewApplication(t) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - TxRecords: trs, - TxResults: txResults, - AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: txResults, + AppHash: make([]byte, crypto.DefaultAppHashSize), + AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) @@ -962,9 +1041,10 @@ func TestPrepareProposalAddedTxsIncluded(t *testing.T) { app := abcimocks.NewApplication(t) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), - TxRecords: trs, - TxResults: txres, + AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: txres, + AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) @@ -1022,9 +1102,10 @@ func TestPrepareProposalReorderTxs(t *testing.T) { app := abcimocks.NewApplication(t) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - AppHash: make([]byte, crypto.DefaultAppHashSize), - TxRecords: trs, - TxResults: txresults, + AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: txresults, + AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) @@ -1087,9 +1168,10 @@ func TestPrepareProposalErrorOnTooManyTxs(t *testing.T) { app := abcimocks.NewApplication(t) app.On("PrepareProposal", mock.Anything, mock.Anything).Return(&abci.ResponsePrepareProposal{ - TxRecords: trs, - TxResults: factory.ExecTxResults(txs), - AppHash: make([]byte, crypto.DefaultAppHashSize), + TxRecords: trs, + TxResults: factory.ExecTxResults(txs), + AppHash: make([]byte, crypto.DefaultAppHashSize), + AppVersion: 1, }, nil) cc := abciclient.NewLocalClient(logger, app) diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index ae4b33e599..2aa8e74713 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -258,7 +258,8 @@ func (app *testApp) PrepareProposal(_ context.Context, req *abci.RequestPrepareP AppVersion: 1, }, }, - TxResults: resTxs, + AppVersion: 1, + TxResults: resTxs, }, nil } diff --git a/internal/state/state_test.go b/internal/state/state_test.go index 942dae3e1c..b308648b28 100644 --- a/internal/state/state_test.go +++ b/internal/state/state_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/require" dbm "github.com/tendermint/tm-db" + "github.com/dashpay/tenderdash/abci/example/kvstore" abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/config" "github.com/dashpay/tenderdash/crypto" @@ -1000,6 +1001,8 @@ func TestStateMakeBlock(t *testing.T) { proposerProTxHash := state.Validators.GetProposer().ProTxHash stateVersion := state.Version.Consensus + // temporary workaround; state.Version.Consensus is deprecated and will be removed + stateVersion.App = kvstore.ProtocolVersion var height int64 = 2 state.LastBlockHeight = height - 1 block, err := statefactory.MakeBlock(state, height, new(types.Commit), 0) diff --git a/internal/state/test/factory/block.go b/internal/state/test/factory/block.go index feff7ec174..49ad77261d 100644 --- a/internal/state/test/factory/block.go +++ b/internal/state/test/factory/block.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/dashpay/tenderdash/abci/example/kvstore" abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/crypto" sm "github.com/dashpay/tenderdash/internal/state" @@ -67,6 +68,10 @@ func MakeBlock(state sm.State, height int64, c *types.Commit, proposedAppVersion if block.ResultsHash, err = abci.TxResultsHash(factory.ExecTxResults(block.Txs)); err != nil { return nil, err } + // this should be set by PrepareProposal, but we don't always call PrepareProposal + if block.Version.App == 0 { + block.Version.App = kvstore.ProtocolVersion + } return block, nil } diff --git a/internal/state/tx_filter_test.go b/internal/state/tx_filter_test.go index bec5162434..3456fed3b1 100644 --- a/internal/state/tx_filter_test.go +++ b/internal/state/tx_filter_test.go @@ -15,7 +15,7 @@ import ( func TestTxFilter(t *testing.T) { const maxBlockBytes = 3241 - maxTxSize := maxBlockBytes - 1131 + maxTxSize := maxBlockBytes - 1132 genDoc := factory.MinimalGenesisDoc() genDoc.ConsensusParams.Block.MaxBytes = maxBlockBytes genDoc.ConsensusParams.Evidence.MaxBytes = 1500 diff --git a/internal/state/validation.go b/internal/state/validation.go index e197b02d59..89914093c8 100644 --- a/internal/state/validation.go +++ b/internal/state/validation.go @@ -27,9 +27,9 @@ func validateBlock(state State, block *types.Block) error { } // Validate basic info. - if block.Version.App != state.Version.Consensus.App || - block.Version.Block != state.Version.Consensus.Block { - return fmt.Errorf("wrong Block.Header.Version. Expected %v, got %v", + // We don't validate app version because proposer can override it on a block-by-block basis. + if block.Version.Block != state.Version.Consensus.Block { + return fmt.Errorf("wrong Block.Header.Version.Block. Expected %v, got %v", state.Version.Consensus, block.Version, ) diff --git a/internal/state/validation_test.go b/internal/state/validation_test.go index d3bab08967..4f92fdffa7 100644 --- a/internal/state/validation_test.go +++ b/internal/state/validation_test.go @@ -3,6 +3,7 @@ package state_test import ( "context" "errors" + "fmt" "strings" "testing" "time" @@ -93,7 +94,6 @@ func TestValidateBlockHeader(t *testing.T) { malleateBlock func(block *types.Block) }{ {"Version wrong1", func(block *types.Block) { block.Version = wrongVersion1 }}, - {"Version wrong2", func(block *types.Block) { block.Version = wrongVersion2 }}, {"ChainID wrong", func(block *types.Block) { block.ChainID = "not-the-real-one" }}, {"Height wrong", func(block *types.Block) { block.Height += 10 }}, {"Core Height does not match chain lock", func(block *types.Block) { @@ -126,11 +126,6 @@ func TestValidateBlockHeader(t *testing.T) { "Proposer invalid", func(block *types.Block) { block.ProposerProTxHash = []byte("wrong size") }, }, - // Set appVersion to 2 allow "invalid proposed app version" case - { - "Proposed app version is invalid", - func(block *types.Block) { block.ProposedAppVersion = 1; state.Version.Consensus.App = 2 }, - }, } // Set appVersion to 2 allow "invalid proposed app version" case @@ -142,16 +137,18 @@ func TestValidateBlockHeader(t *testing.T) { Invalid blocks don't pass */ for _, tc := range testCases { - block, err := statefactory.MakeBlock(state, height, lastCommit, 0) - require.NoError(t, err) - err = changes.UpdateBlock(block) - assert.NoError(t, err) + t.Run(fmt.Sprintf("H:%d/%s", height, tc.name), func(t *testing.T) { + block, err := statefactory.MakeBlock(state, height, lastCommit, 0) + require.NoError(t, err) + err = changes.UpdateBlock(block) + assert.NoError(t, err) - tc.malleateBlock(block) + tc.malleateBlock(block) - err = blockExec.ValidateBlockWithRoundState(ctx, state, changes, block) - t.Logf("%s: %v", tc.name, err) - require.Error(t, err, tc.name) + err = blockExec.ValidateBlockWithRoundState(ctx, state, changes, block) + t.Logf("%s: %v", tc.name, err) + require.Error(t, err, tc.name) + }) } /* diff --git a/node/node_test.go b/node/node_test.go index 43b526bd76..2d085c33f3 100644 --- a/node/node_test.go +++ b/node/node_test.go @@ -505,6 +505,7 @@ func TestMaxProposalBlockSize(t *testing.T) { app, err := kvstore.NewMemoryApp( kvstore.WithLogger(logger.With("module", "kvstore")), kvstore.WithState(math.MaxInt64-1, nil), + kvstore.WithAppVersion(math.MaxUint64), ) require.NoError(t, err) @@ -614,7 +615,7 @@ func TestMaxProposalBlockSize(t *testing.T) { require.Equal(t, types.MaxHeaderBytes, int64(pb.Header.Size())) require.Equal(t, types.MaxCommitOverheadBytes, int64(pb.LastCommit.Size())) // make sure that the block is less than the max possible size - assert.Equal(t, int64(1115+cfg.Mempool.MaxTxBytes), int64(pb.Size())) + assert.Equal(t, int64(1116+cfg.Mempool.MaxTxBytes), int64(pb.Size())) // because of the proto overhead we expect the part set bytes to be equal or // less than the pb block size assert.LessOrEqual(t, partSet.ByteSize(), int64(pb.Size())) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 85c0b2fc7c..aa59ef9990 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -54,7 +54,7 @@ message RequestFlush {} // // Used to sync Tenderdash with the application during a handshake that happens on startup. // The returned app_version will be included in the Header of every block. -// Tenderdsah expects last_block_app_hash and last_block_height to be updated during Commit, +// Tenderdash expects last_block_app_hash and last_block_height to be updated during Commit, // ensuring that Commit is never called twice for the same block height. message RequestInfo { string version = 1; // The Tenderdash software semantic version. @@ -290,6 +290,7 @@ message RequestPrepareProposal { // Proposer's latest available app protocol version. uint64 proposed_app_version = 11; // App and block version used to generate the block. + // App version included in the block can be modified by setting ResponsePrepareProposal.app_version. tendermint.version.Consensus version = 12; // quorum_hash contains hash of validator quorum that will sign the block bytes quorum_hash = 13; @@ -365,6 +366,7 @@ message RequestProcessProposal { // Proposer's latest available app protocol version. uint64 proposed_app_version = 12; // App and block version used to generate the block. + // App version MUST be verified by the app. tendermint.version.Consensus version = 13; // quorum_hash contains hash of validator quorum that will sign the block bytes quorum_hash = 14; @@ -637,6 +639,8 @@ message ResponsePrepareProposal { tendermint.types.CoreChainLock core_chain_lock_update = 5; // Changes to validator set that will be applied at next height. ValidatorSetUpdate validator_set_update = 6 [(gogoproto.nullable) = true]; + // Application version that was used to create the current proposal. + uint64 app_version = 7; } message ResponseProcessProposal { diff --git a/proto/tendermint/types/params.pb.go b/proto/tendermint/types/params.pb.go index e8573e5a47..0ae29224bd 100644 --- a/proto/tendermint/types/params.pb.go +++ b/proto/tendermint/types/params.pb.go @@ -33,6 +33,8 @@ type ConsensusParams struct { Block *BlockParams `protobuf:"bytes,1,opt,name=block,proto3" json:"block,omitempty"` Evidence *EvidenceParams `protobuf:"bytes,2,opt,name=evidence,proto3" json:"evidence,omitempty"` Validator *ValidatorParams `protobuf:"bytes,3,opt,name=validator,proto3" json:"validator,omitempty"` + // DEPRECATED. This will be removed in a future release. + // Replaced by ResponsePrepareProposal.app_version Version *VersionParams `protobuf:"bytes,4,opt,name=version,proto3" json:"version,omitempty"` Synchrony *SynchronyParams `protobuf:"bytes,5,opt,name=synchrony,proto3" json:"synchrony,omitempty"` Timeout *TimeoutParams `protobuf:"bytes,6,opt,name=timeout,proto3" json:"timeout,omitempty"` @@ -298,6 +300,7 @@ func (m *ValidatorParams) GetPubKeyTypes() []string { } // VersionParams contains the ABCI application version. +// DEPRECATED. This will be removed in a future release. type VersionParams struct { AppVersion uint64 `protobuf:"varint,1,opt,name=app_version,json=appVersion,proto3" json:"app_version,omitempty"` } diff --git a/proto/tendermint/types/params.proto b/proto/tendermint/types/params.proto index 5d0ce28cc6..e69beb9364 100644 --- a/proto/tendermint/types/params.proto +++ b/proto/tendermint/types/params.proto @@ -14,6 +14,8 @@ message ConsensusParams { BlockParams block = 1; EvidenceParams evidence = 2; ValidatorParams validator = 3; + // DEPRECATED. This will be removed in a future release. + // Replaced by ResponsePrepareProposal.app_version VersionParams version = 4; SynchronyParams synchrony = 5; TimeoutParams timeout = 6; @@ -59,6 +61,7 @@ message ValidatorParams { } // VersionParams contains the ABCI application version. +// DEPRECATED. This will be removed in a future release. message VersionParams { uint64 app_version = 1; } diff --git a/rpc/client/mock/abci.go b/rpc/client/mock/abci.go index ddc22692e1..fea049ad11 100644 --- a/rpc/client/mock/abci.go +++ b/rpc/client/mock/abci.go @@ -3,13 +3,16 @@ package mock import ( "context" + "github.com/dashpay/tenderdash/abci/example/kvstore" abci "github.com/dashpay/tenderdash/abci/types" "github.com/dashpay/tenderdash/internal/proxy" "github.com/dashpay/tenderdash/libs/bytes" tmproto "github.com/dashpay/tenderdash/proto/tendermint/types" + "github.com/dashpay/tenderdash/proto/tendermint/version" "github.com/dashpay/tenderdash/rpc/client" "github.com/dashpay/tenderdash/rpc/coretypes" "github.com/dashpay/tenderdash/types" + tmversion "github.com/dashpay/tenderdash/version" ) // ABCIApp will send all abci related request to the named app, @@ -65,7 +68,11 @@ func (a ABCIApp) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes if res.CheckTx.IsErr() { return res, nil } - propResp, err := a.App.ProcessProposal(ctx, &abci.RequestProcessProposal{Height: 1, Txs: [][]byte{tx}}) + propResp, err := a.App.ProcessProposal(ctx, &abci.RequestProcessProposal{ + Height: 1, + Txs: [][]byte{tx}, + Version: &version.Consensus{Block: tmversion.BlockProtocol, App: kvstore.ProtocolVersion}, + }) if err != nil { return nil, err } diff --git a/spec/abci++/api.md b/spec/abci++/api.md index 829e9e82af..b1301f9af3 100644 --- a/spec/abci++/api.md +++ b/spec/abci++/api.md @@ -443,7 +443,7 @@ Return information about the application state. Used to sync Tenderdash with the application during a handshake that happens on startup. The returned app_version will be included in the Header of every block. -Tenderdsah expects last_block_app_hash and last_block_height to be updated during Commit, +Tenderdash expects last_block_app_hash and last_block_height to be updated during Commit, ensuring that Commit is never called twice for the same block height. @@ -642,7 +642,7 @@ Note that, if _p_ has a non-`nil` _validValue_, Tenderdash will use it as propos | core_chain_locked_height | [uint32](#uint32) | | Core chain lock height to be used when signing this block. | | proposer_pro_tx_hash | [bytes](#bytes) | | ProTxHash of the original proposer of the block. | | proposed_app_version | [uint64](#uint64) | | Proposer's latest available app protocol version. | -| version | [tendermint.version.Consensus](#tendermint-version-Consensus) | | App and block version used to generate the block. | +| version | [tendermint.version.Consensus](#tendermint-version-Consensus) | | App and block version used to generate the block. App version included in the block can be modified by setting ResponsePrepareProposal.app_version. | | quorum_hash | [bytes](#bytes) | | quorum_hash contains hash of validator quorum that will sign the block | @@ -712,7 +712,7 @@ When a validator _p_ enters Tenderdash consensus round _r_, height _h_, in which | core_chain_lock_update | [tendermint.types.CoreChainLock](#tendermint-types-CoreChainLock) | | Next core-chain-lock-update for validation in ABCI. | | proposer_pro_tx_hash | [bytes](#bytes) | | ProTxHash of the original proposer of the block. | | proposed_app_version | [uint64](#uint64) | | Proposer's latest available app protocol version. | -| version | [tendermint.version.Consensus](#tendermint-version-Consensus) | | App and block version used to generate the block. | +| version | [tendermint.version.Consensus](#tendermint-version-Consensus) | | App and block version used to generate the block. App version MUST be verified by the app. | | quorum_hash | [bytes](#bytes) | | quorum_hash contains hash of validator quorum that will sign the block | @@ -1026,6 +1026,7 @@ nondeterministic | consensus_param_updates | [tendermint.types.ConsensusParams](#tendermint-types-ConsensusParams) | | Changes to consensus-critical gas, size, and other parameters that will be applied at next height. | | core_chain_lock_update | [tendermint.types.CoreChainLock](#tendermint-types-CoreChainLock) | | Core chain lock that will be used for next block. | | validator_set_update | [ValidatorSetUpdate](#tendermint-abci-ValidatorSetUpdate) | | Changes to validator set that will be applied at next height. | +| app_version | [uint64](#uint64) | | Application version that was used to create the current proposal. | diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index 4744164aab..29121647f4 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -51,6 +51,7 @@ func NewApplication(cfg kvstore.Config, opts ...kvstore.OptFunc) (*Application, kvstore.WithLogger(logger.With("module", "kvstore")), kvstore.WithVerifyTxFunc(verifyTx), kvstore.WithPrepareTxsFunc(prepareTxs), + kvstore.WithAppVersion(0), }, opts...) app := Application{ logger: logger.With("module", "kvstore"), diff --git a/test/e2e/tests/app_test.go b/test/e2e/tests/app_test.go index 6430f802f6..77186b95f3 100644 --- a/test/e2e/tests/app_test.go +++ b/test/e2e/tests/app_test.go @@ -354,3 +354,21 @@ func TestApp_TxTooBig(t *testing.T) { includeInBlockTimeout.String(), ) } + +// Tests that the app version in most recent block is set to height of the block. +// Requires kvstore.WithEnforceVersionToHeight() to be enabled. +func TestApp_AppVersion(t *testing.T) { + testNode(t, func(ctx context.Context, t *testing.T, node e2e.Node) { + client, err := node.Client() + require.NoError(t, err) + info, err := client.ABCIInfo(ctx) + require.NoError(t, err) + require.NotZero(t, info.Response.LastBlockHeight) + + block, err := client.Block(ctx, &info.Response.LastBlockHeight) + require.NoError(t, err) + + require.Equal(t, info.Response.LastBlockHeight, block.Block.Height) + require.EqualValues(t, block.Block.Height, block.Block.Version.App) + }) +} diff --git a/types/block.go b/types/block.go index 6af0a815ab..fcace70bfb 100644 --- a/types/block.go +++ b/types/block.go @@ -32,7 +32,7 @@ const ( // MaxHeaderBytes is a maximum header size. // NOTE: Because app hash can be of arbitrary size, the header is therefore not // capped in size and thus this number should be seen as a soft max - MaxHeaderBytes int64 = 725 + MaxHeaderBytes int64 = 726 MaxCoreChainLockSize int64 = 132 // MaxOverheadForBlock - maximum overhead to encode a block (up to diff --git a/types/block_test.go b/types/block_test.go index d7b263ab86..2803f8f1cc 100644 --- a/types/block_test.go +++ b/types/block_test.go @@ -499,7 +499,7 @@ func TestMaxHeaderBytes(t *testing.T) { timestamp := time.Date(math.MaxInt64, 0, 0, 0, 0, 0, math.MaxInt64, time.UTC) h := Header{ - Version: version.Consensus{Block: math.MaxInt64, App: math.MaxInt64}, + Version: version.Consensus{Block: math.MaxInt64, App: math.MaxUint64}, ChainID: maxChainID, Height: math.MaxInt64, Time: timestamp, @@ -559,7 +559,7 @@ func TestBlockMaxDataBytes(t *testing.T) { require.NotNil(t, commit) // minBlockSize is minimum correct size of a block - const minBlockSize = 1370 + const minBlockSize = 1371 testCases := []struct { maxBytes int64 @@ -596,7 +596,7 @@ func TestBlockMaxDataBytes(t *testing.T) { func TestBlockMaxDataBytesNoEvidence(t *testing.T) { // minBlockSize is minimum correct size of a block - const minBlockSize = 1128 + const minBlockSize = 1129 testCases := []struct { maxBytes int64