From a600873a3018a34cf118fb4f83955b0eed95e1fe Mon Sep 17 00:00:00 2001 From: Uday Patil Date: Fri, 19 Apr 2024 12:13:17 -0500 Subject: [PATCH] Revert "Merge seiv2 into main (#232)" This reverts commit 754c03aa8e9a1ad8216d587dcb7733635cd53c06. --- abci/client/grpc_client.go | 5 +- abci/client/mocks/client.go | 8 +- abci/client/socket_client.go | 4 +- abci/example/kvstore/kvstore.go | 4 +- abci/server/grpc_server.go | 8 - abci/types/application.go | 6 +- abci/types/messages.go | 4 +- abci/types/mocks/application.go | 8 +- abci/types/types.go | 25 - abci/types/types.pb.go | 942 +++++++----------------- config/config.go | 14 - config/toml.go | 8 - internal/consensus/mempool_test.go | 13 +- internal/consensus/reactor.go | 11 +- internal/consensus/reactor_test.go | 2 - internal/mempool/mempool.go | 319 +++----- internal/mempool/mempool_test.go | 246 +------ internal/mempool/metrics.gen.go | 28 - internal/mempool/metrics.go | 15 - internal/mempool/priority_queue.go | 395 +--------- internal/mempool/priority_queue_test.go | 283 +------ internal/mempool/tx.go | 164 +---- internal/mempool/tx_test.go | 133 ---- internal/proxy/client.go | 2 +- internal/rpc/core/mempool.go | 5 +- internal/state/helpers_test.go | 4 +- node/node.go | 1 - proto/tendermint/abci/types.proto | 8 - proto/tendermint/crypto/keys.pb.go | 1 + proto/tendermint/mempool/types.pb.go | 1 + proto/tendermint/p2p/conn.pb.go | 1 + proto/tendermint/types/types.pb.go | 1 + rpc/client/mock/abci.go | 2 +- test/e2e/app/app.go | 10 +- types/mempool.go | 20 - types/tx.go | 2 +- 36 files changed, 440 insertions(+), 2263 deletions(-) diff --git a/abci/client/grpc_client.go b/abci/client/grpc_client.go index 8eec13ef8..f1be2c120 100644 --- a/abci/client/grpc_client.go +++ b/abci/client/grpc_client.go @@ -130,9 +130,8 @@ func (cli *grpcClient) Info(ctx context.Context, params *types.RequestInfo) (*ty return cli.client.Info(ctx, types.ToRequestInfo(params).GetInfo(), grpc.WaitForReady(true)) } -func (cli *grpcClient) CheckTx(ctx context.Context, params *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { - resCheckTx, err := cli.client.CheckTx(ctx, types.ToRequestCheckTx(params).GetCheckTx(), grpc.WaitForReady(true)) - return &types.ResponseCheckTxV2{ResponseCheckTx: resCheckTx}, err +func (cli *grpcClient) CheckTx(ctx context.Context, params *types.RequestCheckTx) (*types.ResponseCheckTx, error) { + return cli.client.CheckTx(ctx, types.ToRequestCheckTx(params).GetCheckTx(), grpc.WaitForReady(true)) } func (cli *grpcClient) Query(ctx context.Context, params *types.RequestQuery) (*types.ResponseQuery, error) { diff --git a/abci/client/mocks/client.go b/abci/client/mocks/client.go index a0626cff0..44a5eb00f 100644 --- a/abci/client/mocks/client.go +++ b/abci/client/mocks/client.go @@ -38,15 +38,15 @@ func (_m *Client) ApplySnapshotChunk(_a0 context.Context, _a1 *types.RequestAppl } // CheckTx provides a mock function with given fields: _a0, _a1 -func (_m *Client) CheckTx(_a0 context.Context, _a1 *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { +func (_m *Client) CheckTx(_a0 context.Context, _a1 *types.RequestCheckTx) (*types.ResponseCheckTx, error) { ret := _m.Called(_a0, _a1) - var r0 *types.ResponseCheckTxV2 - if rf, ok := ret.Get(0).(func(context.Context, *types.RequestCheckTx) *types.ResponseCheckTxV2); ok { + var r0 *types.ResponseCheckTx + if rf, ok := ret.Get(0).(func(context.Context, *types.RequestCheckTx) *types.ResponseCheckTx); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.ResponseCheckTxV2) + r0 = ret.Get(0).(*types.ResponseCheckTx) } } diff --git a/abci/client/socket_client.go b/abci/client/socket_client.go index 35f244666..80f106333 100644 --- a/abci/client/socket_client.go +++ b/abci/client/socket_client.go @@ -257,12 +257,12 @@ func (cli *socketClient) Info(ctx context.Context, req *types.RequestInfo) (*typ return res.GetInfo(), nil } -func (cli *socketClient) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { +func (cli *socketClient) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { res, err := cli.doRequest(ctx, types.ToRequestCheckTx(req)) if err != nil { return nil, err } - return &types.ResponseCheckTxV2{ResponseCheckTx: res.GetCheckTx()}, nil + return res.GetCheckTx(), nil } func (cli *socketClient) Query(ctx context.Context, req *types.RequestQuery) (*types.ResponseQuery, error) { diff --git a/abci/example/kvstore/kvstore.go b/abci/example/kvstore/kvstore.go index ac0d122b1..f33ff2be1 100644 --- a/abci/example/kvstore/kvstore.go +++ b/abci/example/kvstore/kvstore.go @@ -205,8 +205,8 @@ func (app *Application) FinalizeBlock(_ context.Context, req *types.RequestFinal return &types.ResponseFinalizeBlock{TxResults: respTxs, ValidatorUpdates: app.ValUpdates, AppHash: appHash}, nil } -func (*Application) CheckTx(_ context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { - return &types.ResponseCheckTxV2{ResponseCheckTx: &types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}}, nil +func (*Application) CheckTx(_ context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { + return &types.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}, nil } func (app *Application) Commit(_ context.Context) (*types.ResponseCommit, error) { diff --git a/abci/server/grpc_server.go b/abci/server/grpc_server.go index 6f7caf39c..0dfee8169 100644 --- a/abci/server/grpc_server.go +++ b/abci/server/grpc_server.go @@ -81,11 +81,3 @@ func (app *gRPCApplication) Flush(_ context.Context, req *types.RequestFlush) (* func (app *gRPCApplication) Commit(ctx context.Context, req *types.RequestCommit) (*types.ResponseCommit, error) { return app.Application.Commit(ctx) } - -func (app *gRPCApplication) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { - resV2, err := app.Application.CheckTx(ctx, req) - if err != nil { - return &types.ResponseCheckTx{}, err - } - return resV2.ResponseCheckTx, nil -} diff --git a/abci/types/application.go b/abci/types/application.go index 5f98bdc9f..9915d16a1 100644 --- a/abci/types/application.go +++ b/abci/types/application.go @@ -12,7 +12,7 @@ type Application interface { Query(context.Context, *RequestQuery) (*ResponseQuery, error) // Query for state // Mempool Connection - CheckTx(context.Context, *RequestCheckTx) (*ResponseCheckTxV2, error) // Validate a tx for the mempool + CheckTx(context.Context, *RequestCheckTx) (*ResponseCheckTx, error) // Validate a tx for the mempool // Consensus Connection InitChain(context.Context, *RequestInitChain) (*ResponseInitChain, error) // Initialize blockchain w validators/other info from TendermintCore @@ -51,8 +51,8 @@ func (BaseApplication) Info(_ context.Context, req *RequestInfo) (*ResponseInfo, return &ResponseInfo{}, nil } -func (BaseApplication) CheckTx(_ context.Context, req *RequestCheckTx) (*ResponseCheckTxV2, error) { - return &ResponseCheckTxV2{ResponseCheckTx: &ResponseCheckTx{Code: CodeTypeOK}}, nil +func (BaseApplication) CheckTx(_ context.Context, req *RequestCheckTx) (*ResponseCheckTx, error) { + return &ResponseCheckTx{Code: CodeTypeOK}, nil } func (BaseApplication) Commit(_ context.Context) (*ResponseCommit, error) { diff --git a/abci/types/messages.go b/abci/types/messages.go index f6a6c12d1..2ab6ac1df 100644 --- a/abci/types/messages.go +++ b/abci/types/messages.go @@ -155,9 +155,9 @@ func ToResponseInfo(res *ResponseInfo) *Response { } } -func ToResponseCheckTx(res *ResponseCheckTxV2) *Response { +func ToResponseCheckTx(res *ResponseCheckTx) *Response { return &Response{ - Value: &Response_CheckTx{res.ResponseCheckTx}, + Value: &Response_CheckTx{res}, } } diff --git a/abci/types/mocks/application.go b/abci/types/mocks/application.go index 08ef9ca5c..c6eb29219 100644 --- a/abci/types/mocks/application.go +++ b/abci/types/mocks/application.go @@ -38,15 +38,15 @@ func (_m *Application) ApplySnapshotChunk(_a0 context.Context, _a1 *types.Reques } // CheckTx provides a mock function with given fields: _a0, _a1 -func (_m *Application) CheckTx(_a0 context.Context, _a1 *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { +func (_m *Application) CheckTx(_a0 context.Context, _a1 *types.RequestCheckTx) (*types.ResponseCheckTx, error) { ret := _m.Called(_a0, _a1) - var r0 *types.ResponseCheckTxV2 - if rf, ok := ret.Get(0).(func(context.Context, *types.RequestCheckTx) *types.ResponseCheckTxV2); ok { + var r0 *types.ResponseCheckTx + if rf, ok := ret.Get(0).(func(context.Context, *types.RequestCheckTx) *types.ResponseCheckTx); ok { r0 = rf(_a0, _a1) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*types.ResponseCheckTxV2) + r0 = ret.Get(0).(*types.ResponseCheckTx) } } diff --git a/abci/types/types.go b/abci/types/types.go index 1ecb0a9f3..121e72159 100644 --- a/abci/types/types.go +++ b/abci/types/types.go @@ -237,28 +237,3 @@ func MarshalTxResults(r []*ExecTxResult) ([][]byte, error) { } return s, nil } - -type PendingTxCheckerResponse int - -const ( - Accepted PendingTxCheckerResponse = iota - Rejected - Pending -) - -type PendingTxChecker func() PendingTxCheckerResponse -type ExpireTxHandler func() - -// ResponseCheckTxV2 response type contains non-protobuf fields, so non-local ABCI clients will not be able -// to utilize the new fields in V2 type (but still be backwards-compatible) -type ResponseCheckTxV2 struct { - *ResponseCheckTx - IsPendingTransaction bool - Checker PendingTxChecker // must not be nil if IsPendingTransaction is true - ExpireTxHandler ExpireTxHandler - - // helper properties for prioritization in mempool - EVMNonce uint64 - EVMSenderAddress string - IsEVM bool -} diff --git a/abci/types/types.pb.go b/abci/types/types.pb.go index 74b4620e1..e28ce2827 100644 --- a/abci/types/types.pb.go +++ b/abci/types/types.pb.go @@ -217,7 +217,6 @@ func (ResponseVerifyVoteExtension_VerifyStatus) EnumDescriptor() ([]byte, []int) } // TxAction contains App-provided information on what to do with a transaction that is part of a raw proposal -// Deprecate entire usage: https://github.com/tendermint/tendermint/pull/9283 type TxRecord_TxAction int32 const ( @@ -2878,15 +2877,14 @@ func (m *ResponseCheckTx) GetPriority() int64 { } type ResponseDeliverTx struct { - Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - Log string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"` - Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` - GasWanted int64 `protobuf:"varint,5,opt,name=gas_wanted,proto3" json:"gas_wanted,omitempty"` - GasUsed int64 `protobuf:"varint,6,opt,name=gas_used,proto3" json:"gas_used,omitempty"` - Events []Event `protobuf:"bytes,7,rep,name=events,proto3" json:"events,omitempty"` - Codespace string `protobuf:"bytes,8,opt,name=codespace,proto3" json:"codespace,omitempty"` - EvmTxInfo *EvmTxInfo `protobuf:"bytes,9,opt,name=evm_tx_info,json=evmTxInfo,proto3" json:"evm_tx_info,omitempty"` + Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + Log string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"` + Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` + GasWanted int64 `protobuf:"varint,5,opt,name=gas_wanted,proto3" json:"gas_wanted,omitempty"` + GasUsed int64 `protobuf:"varint,6,opt,name=gas_used,proto3" json:"gas_used,omitempty"` + Events []Event `protobuf:"bytes,7,rep,name=events,proto3" json:"events,omitempty"` + Codespace string `protobuf:"bytes,8,opt,name=codespace,proto3" json:"codespace,omitempty"` } func (m *ResponseDeliverTx) Reset() { *m = ResponseDeliverTx{} } @@ -2978,13 +2976,6 @@ func (m *ResponseDeliverTx) GetCodespace() string { return "" } -func (m *ResponseDeliverTx) GetEvmTxInfo() *EvmTxInfo { - if m != nil { - return m.EvmTxInfo - } - return nil -} - type ResponseEndBlock struct { ValidatorUpdates []ValidatorUpdate `protobuf:"bytes,1,rep,name=validator_updates,json=validatorUpdates,proto3" json:"validator_updates"` ConsensusParamUpdates *ConsensusParams `protobuf:"bytes,2,opt,name=consensus_param_updates,json=consensusParamUpdates,proto3" json:"consensus_param_updates,omitempty"` @@ -3916,15 +3907,14 @@ func (m *EventAttribute) GetIndex() bool { // // * Its structure is equivalent to #ResponseDeliverTx which will be deprecated/deleted type ExecTxResult struct { - Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` - Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` - Log string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"` - Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` - GasWanted int64 `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"` - GasUsed int64 `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` - Events []Event `protobuf:"bytes,7,rep,name=events,proto3" json:"events,omitempty"` - Codespace string `protobuf:"bytes,8,opt,name=codespace,proto3" json:"codespace,omitempty"` - EvmTxInfo *EvmTxInfo `protobuf:"bytes,9,opt,name=evm_tx_info,json=evmTxInfo,proto3" json:"evm_tx_info,omitempty"` + Code uint32 `protobuf:"varint,1,opt,name=code,proto3" json:"code,omitempty"` + Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"` + Log string `protobuf:"bytes,3,opt,name=log,proto3" json:"log,omitempty"` + Info string `protobuf:"bytes,4,opt,name=info,proto3" json:"info,omitempty"` + GasWanted int64 `protobuf:"varint,5,opt,name=gas_wanted,json=gasWanted,proto3" json:"gas_wanted,omitempty"` + GasUsed int64 `protobuf:"varint,6,opt,name=gas_used,json=gasUsed,proto3" json:"gas_used,omitempty"` + Events []Event `protobuf:"bytes,7,rep,name=events,proto3" json:"events,omitempty"` + Codespace string `protobuf:"bytes,8,opt,name=codespace,proto3" json:"codespace,omitempty"` } func (m *ExecTxResult) Reset() { *m = ExecTxResult{} } @@ -4016,13 +4006,6 @@ func (m *ExecTxResult) GetCodespace() string { return "" } -func (m *ExecTxResult) GetEvmTxInfo() *EvmTxInfo { - if m != nil { - return m.EvmTxInfo - } - return nil -} - // TxResult contains results of executing the transaction. // // One usage is indexing transaction results. @@ -4656,66 +4639,6 @@ func (m *Evidence) GetTotalVotingPower() int64 { return 0 } -type EvmTxInfo struct { - SenderAddress string `protobuf:"bytes,1,opt,name=senderAddress,proto3" json:"senderAddress,omitempty"` - Nonce uint64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` - TxHash string `protobuf:"bytes,3,opt,name=txHash,proto3" json:"txHash,omitempty"` -} - -func (m *EvmTxInfo) Reset() { *m = EvmTxInfo{} } -func (m *EvmTxInfo) String() string { return proto.CompactTextString(m) } -func (*EvmTxInfo) ProtoMessage() {} -func (*EvmTxInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{59} -} -func (m *EvmTxInfo) XXX_Unmarshal(b []byte) error { - return m.Unmarshal(b) -} -func (m *EvmTxInfo) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - if deterministic { - return xxx_messageInfo_EvmTxInfo.Marshal(b, m, deterministic) - } else { - b = b[:cap(b)] - n, err := m.MarshalToSizedBuffer(b) - if err != nil { - return nil, err - } - return b[:n], nil - } -} -func (m *EvmTxInfo) XXX_Merge(src proto.Message) { - xxx_messageInfo_EvmTxInfo.Merge(m, src) -} -func (m *EvmTxInfo) XXX_Size() int { - return m.Size() -} -func (m *EvmTxInfo) XXX_DiscardUnknown() { - xxx_messageInfo_EvmTxInfo.DiscardUnknown(m) -} - -var xxx_messageInfo_EvmTxInfo proto.InternalMessageInfo - -func (m *EvmTxInfo) GetSenderAddress() string { - if m != nil { - return m.SenderAddress - } - return "" -} - -func (m *EvmTxInfo) GetNonce() uint64 { - if m != nil { - return m.Nonce - } - return 0 -} - -func (m *EvmTxInfo) GetTxHash() string { - if m != nil { - return m.TxHash - } - return "" -} - type Snapshot struct { Height uint64 `protobuf:"varint,1,opt,name=height,proto3" json:"height,omitempty"` Format uint32 `protobuf:"varint,2,opt,name=format,proto3" json:"format,omitempty"` @@ -4728,7 +4651,7 @@ func (m *Snapshot) Reset() { *m = Snapshot{} } func (m *Snapshot) String() string { return proto.CompactTextString(m) } func (*Snapshot) ProtoMessage() {} func (*Snapshot) Descriptor() ([]byte, []int) { - return fileDescriptor_252557cfdd89a31a, []int{60} + return fileDescriptor_252557cfdd89a31a, []int{59} } func (m *Snapshot) XXX_Unmarshal(b []byte) error { return m.Unmarshal(b) @@ -4859,262 +4782,256 @@ func init() { proto.RegisterType((*ExtendedVoteInfo)(nil), "tendermint.abci.ExtendedVoteInfo") proto.RegisterType((*Misbehavior)(nil), "tendermint.abci.Misbehavior") proto.RegisterType((*Evidence)(nil), "tendermint.abci.Evidence") - proto.RegisterType((*EvmTxInfo)(nil), "tendermint.abci.EvmTxInfo") proto.RegisterType((*Snapshot)(nil), "tendermint.abci.Snapshot") } func init() { proto.RegisterFile("tendermint/abci/types.proto", fileDescriptor_252557cfdd89a31a) } var fileDescriptor_252557cfdd89a31a = []byte{ - // 3955 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0xcd, 0x93, 0xe3, 0xc6, - 0x75, 0x27, 0xf8, 0x8d, 0xc7, 0x2f, 0x4c, 0xcf, 0xec, 0x2e, 0x97, 0x2b, 0xed, 0xae, 0xa0, 0xac, - 0xb4, 0x5a, 0xc9, 0x33, 0xce, 0x28, 0x92, 0x57, 0x96, 0x1c, 0x85, 0xc3, 0xe5, 0x88, 0xb3, 0x3b, - 0x9a, 0x19, 0x61, 0x38, 0xa3, 0x28, 0x89, 0x05, 0x63, 0xc8, 0x1e, 0x12, 0x5e, 0x92, 0x80, 0x01, - 0x90, 0xe2, 0xe8, 0x94, 0xca, 0xc7, 0xc5, 0xb9, 0xe8, 0x98, 0x43, 0x7c, 0x8b, 0xff, 0x81, 0x1c, - 0x72, 0xc8, 0x21, 0x55, 0xa9, 0x4a, 0xa5, 0x7c, 0xf0, 0xc1, 0x87, 0x54, 0x2a, 0x27, 0x27, 0x25, - 0x55, 0xe5, 0xe0, 0x7f, 0x20, 0x47, 0xa7, 0xfa, 0x03, 0x5f, 0x24, 0xc0, 0x0f, 0xed, 0x56, 0xaa, - 0x54, 0xd6, 0x0d, 0xdd, 0x78, 0xef, 0x35, 0xba, 0xfb, 0xbd, 0xd7, 0xef, 0xfd, 0x5e, 0x03, 0x6e, - 0x39, 0x78, 0xd4, 0xc5, 0xd6, 0x50, 0x1f, 0x39, 0x3b, 0xda, 0x45, 0x47, 0xdf, 0x71, 0xae, 0x4c, - 0x6c, 0x6f, 0x9b, 0x96, 0xe1, 0x18, 0xa8, 0xe2, 0xbf, 0xdc, 0x26, 0x2f, 0x6b, 0x2f, 0x06, 0xa8, - 0x3b, 0xd6, 0x95, 0xe9, 0x18, 0x3b, 0xa6, 0x65, 0x18, 0x97, 0x8c, 0xbe, 0xf6, 0xc2, 0xfc, 0xeb, - 0xa7, 0xf8, 0x8a, 0x4b, 0x0b, 0x31, 0xd3, 0x51, 0x76, 0x4c, 0xcd, 0xd2, 0x86, 0x76, 0x04, 0x33, - 0x7b, 0x1d, 0xf8, 0x94, 0xda, 0x9d, 0x9e, 0x61, 0xf4, 0x06, 0x78, 0x87, 0xb6, 0x2e, 0xc6, 0x97, - 0x3b, 0x8e, 0x3e, 0xc4, 0xb6, 0xa3, 0x0d, 0x4d, 0x4e, 0xb0, 0xd5, 0x33, 0x7a, 0x06, 0x7d, 0xdc, - 0x21, 0x4f, 0xac, 0x57, 0xfe, 0x65, 0x01, 0x72, 0x0a, 0xfe, 0xc9, 0x18, 0xdb, 0x0e, 0xda, 0x85, - 0x34, 0xee, 0xf4, 0x8d, 0xaa, 0x70, 0x57, 0xb8, 0x5f, 0xd8, 0x7d, 0x61, 0x7b, 0x66, 0x72, 0xdb, - 0x9c, 0xae, 0xd9, 0xe9, 0x1b, 0xad, 0x84, 0x42, 0x69, 0xd1, 0x5b, 0x90, 0xb9, 0x1c, 0x8c, 0xed, - 0x7e, 0x35, 0x49, 0x99, 0x5e, 0x8c, 0x63, 0xda, 0x27, 0x44, 0xad, 0x84, 0xc2, 0xa8, 0xc9, 0x50, - 0xfa, 0xe8, 0xd2, 0xa8, 0xa6, 0x16, 0x0f, 0x75, 0x30, 0xba, 0xa4, 0x43, 0x11, 0x5a, 0xb4, 0x07, - 0xa0, 0x8f, 0x74, 0x47, 0xed, 0xf4, 0x35, 0x7d, 0x54, 0x4d, 0x53, 0xce, 0x97, 0xe2, 0x39, 0x75, - 0xa7, 0x41, 0x08, 0x5b, 0x09, 0x45, 0xd4, 0xdd, 0x06, 0xf9, 0xdc, 0x9f, 0x8c, 0xb1, 0x75, 0x55, - 0xcd, 0x2c, 0xfe, 0xdc, 0x8f, 0x08, 0x11, 0xf9, 0x5c, 0x4a, 0x8d, 0xde, 0x83, 0x7c, 0xa7, 0x8f, - 0x3b, 0x4f, 0x55, 0x67, 0x5a, 0xcd, 0x51, 0xce, 0x3b, 0x71, 0x9c, 0x0d, 0x42, 0xd7, 0x9e, 0xb6, - 0x12, 0x4a, 0xae, 0xc3, 0x1e, 0xd1, 0x43, 0xc8, 0x76, 0x8c, 0xe1, 0x50, 0x77, 0xaa, 0x40, 0x79, - 0x6f, 0xc7, 0xf2, 0x52, 0xaa, 0x56, 0x42, 0xe1, 0xf4, 0xe8, 0x08, 0xca, 0x03, 0xdd, 0x76, 0x54, - 0x7b, 0xa4, 0x99, 0x76, 0xdf, 0x70, 0xec, 0x6a, 0x81, 0x4a, 0xb8, 0x17, 0x27, 0xe1, 0x50, 0xb7, - 0x9d, 0x53, 0x97, 0xb8, 0x95, 0x50, 0x4a, 0x83, 0x60, 0x07, 0x91, 0x67, 0x5c, 0x5e, 0x62, 0xcb, - 0x13, 0x58, 0x2d, 0x2e, 0x96, 0x77, 0x4c, 0xa8, 0x5d, 0x7e, 0x22, 0xcf, 0x08, 0x76, 0xa0, 0x3f, - 0x85, 0xcd, 0x81, 0xa1, 0x75, 0x3d, 0x71, 0x6a, 0xa7, 0x3f, 0x1e, 0x3d, 0xad, 0x96, 0xa8, 0xd0, - 0xd7, 0x62, 0x3f, 0xd2, 0xd0, 0xba, 0xae, 0x88, 0x06, 0x61, 0x68, 0x25, 0x94, 0x8d, 0xc1, 0x6c, - 0x27, 0xfa, 0x14, 0xb6, 0x34, 0xd3, 0x1c, 0x5c, 0xcd, 0x4a, 0x2f, 0x53, 0xe9, 0x0f, 0xe2, 0xa4, - 0xd7, 0x09, 0xcf, 0xac, 0x78, 0xa4, 0xcd, 0xf5, 0xa2, 0x36, 0x48, 0xa6, 0x85, 0x4d, 0xcd, 0xc2, - 0xaa, 0x69, 0x19, 0xa6, 0x61, 0x6b, 0x83, 0x6a, 0x85, 0xca, 0x7e, 0x35, 0x4e, 0xf6, 0x09, 0xa3, - 0x3f, 0xe1, 0xe4, 0xad, 0x84, 0x52, 0x31, 0xc3, 0x5d, 0x4c, 0xaa, 0xd1, 0xc1, 0xb6, 0xed, 0x4b, - 0x95, 0x96, 0x49, 0xa5, 0xf4, 0x61, 0xa9, 0xa1, 0x2e, 0xd4, 0x84, 0x02, 0x9e, 0x12, 0x76, 0x75, - 0x62, 0x38, 0xb8, 0xba, 0x41, 0x05, 0xca, 0xb1, 0x16, 0x4a, 0x49, 0xcf, 0x0d, 0x07, 0xb7, 0x12, - 0x0a, 0x60, 0xaf, 0x85, 0x34, 0xb8, 0x36, 0xc1, 0x96, 0x7e, 0x79, 0x45, 0xc5, 0xa8, 0xf4, 0x8d, - 0xad, 0x1b, 0xa3, 0x2a, 0xa2, 0x02, 0x5f, 0x8f, 0x13, 0x78, 0x4e, 0x99, 0x88, 0x88, 0xa6, 0xcb, - 0xd2, 0x4a, 0x28, 0x9b, 0x93, 0xf9, 0x6e, 0xa2, 0x62, 0x97, 0xfa, 0x48, 0x1b, 0xe8, 0x9f, 0x63, - 0xf5, 0x62, 0x60, 0x74, 0x9e, 0x56, 0x37, 0x17, 0xab, 0xd8, 0x3e, 0xa7, 0xde, 0x23, 0xc4, 0x44, - 0xc5, 0x2e, 0x83, 0x1d, 0x64, 0xe6, 0x17, 0xb8, 0xa7, 0x8f, 0xb8, 0xb0, 0xad, 0xc5, 0x33, 0xdf, - 0x23, 0xa4, 0xae, 0x24, 0xb8, 0xf0, 0x5a, 0xc4, 0x79, 0x74, 0xf1, 0x40, 0x9f, 0x60, 0x8b, 0xd8, - 0xf0, 0xb5, 0xc5, 0xce, 0xe3, 0x11, 0xa3, 0xa4, 0x56, 0x2c, 0x76, 0xdd, 0x06, 0x7a, 0x1f, 0x44, - 0xb2, 0x03, 0xec, 0x43, 0xae, 0x53, 0x11, 0x77, 0x63, 0xb7, 0x60, 0xd4, 0x75, 0x3f, 0x23, 0x8f, - 0xf9, 0x33, 0x99, 0x0b, 0x35, 0x97, 0x81, 0xe6, 0x60, 0xdb, 0xa9, 0xde, 0x58, 0x3c, 0x17, 0x62, - 0x26, 0x87, 0x94, 0x92, 0xcc, 0x65, 0xe0, 0xb5, 0xf6, 0x72, 0x90, 0x99, 0x68, 0x83, 0x31, 0x7e, - 0x9c, 0xce, 0x67, 0xa5, 0xdc, 0xe3, 0x74, 0x3e, 0x2f, 0x89, 0x8f, 0xd3, 0x79, 0x51, 0x02, 0xf9, - 0x55, 0x28, 0x04, 0xbc, 0x34, 0xaa, 0x42, 0x6e, 0x88, 0x6d, 0x5b, 0xeb, 0x61, 0xea, 0xd4, 0x45, - 0xc5, 0x6d, 0xca, 0x65, 0x28, 0x06, 0x3d, 0xb3, 0xfc, 0x85, 0xe0, 0x71, 0x12, 0xa7, 0x4b, 0x38, - 0x27, 0xd8, 0xa2, 0xba, 0xc1, 0x39, 0x79, 0x13, 0xbd, 0x0c, 0x25, 0xba, 0x02, 0xaa, 0xfb, 0x9e, - 0x78, 0xfe, 0xb4, 0x52, 0xa4, 0x9d, 0xe7, 0x9c, 0xe8, 0x0e, 0x14, 0xcc, 0x5d, 0xd3, 0x23, 0x49, - 0x51, 0x12, 0x30, 0x77, 0x4d, 0x97, 0xe0, 0x25, 0x28, 0x92, 0xb9, 0x7a, 0x14, 0x69, 0x3a, 0x48, - 0x81, 0xf4, 0x71, 0x12, 0xf9, 0x97, 0x49, 0x90, 0x66, 0xbd, 0x39, 0x7a, 0x08, 0x69, 0x72, 0xb0, - 0xf1, 0x33, 0xaa, 0xb6, 0xcd, 0x4e, 0xbd, 0x6d, 0xf7, 0xd4, 0xdb, 0x6e, 0xbb, 0xa7, 0xde, 0x5e, - 0xfe, 0x17, 0xbf, 0xbe, 0x93, 0xf8, 0xe2, 0xbf, 0xee, 0x08, 0x0a, 0xe5, 0x40, 0x37, 0x89, 0x0f, - 0xd7, 0xf4, 0x91, 0xaa, 0x77, 0xe9, 0x27, 0x8b, 0xc4, 0x41, 0x6b, 0xfa, 0xe8, 0xa0, 0x8b, 0x0e, - 0x41, 0xea, 0x18, 0x23, 0x1b, 0x8f, 0xec, 0xb1, 0xad, 0xb2, 0x33, 0x97, 0x9f, 0x4c, 0x21, 0x15, - 0x61, 0xc7, 0x6d, 0xc3, 0xa5, 0x3c, 0xa1, 0x84, 0x4a, 0xa5, 0x13, 0xee, 0x40, 0xfb, 0x00, 0x13, - 0x6d, 0xa0, 0x77, 0x35, 0xc7, 0xb0, 0xec, 0x6a, 0xfa, 0x6e, 0x2a, 0x52, 0x4f, 0xce, 0x5d, 0x92, - 0x33, 0xb3, 0xab, 0x39, 0x78, 0x2f, 0x4d, 0x3e, 0x57, 0x09, 0x70, 0xa2, 0x57, 0xa0, 0xa2, 0x99, - 0xa6, 0x6a, 0x3b, 0x9a, 0x83, 0xd5, 0x8b, 0x2b, 0x07, 0xdb, 0xf4, 0xd4, 0x2a, 0x2a, 0x25, 0xcd, - 0x34, 0x4f, 0x49, 0xef, 0x1e, 0xe9, 0x44, 0xf7, 0xa0, 0x4c, 0x0e, 0x38, 0x5d, 0x1b, 0xa8, 0x7d, - 0xac, 0xf7, 0xfa, 0x4e, 0x35, 0x7b, 0x57, 0xb8, 0x9f, 0x52, 0x4a, 0xbc, 0xb7, 0x45, 0x3b, 0xe5, - 0xae, 0xb7, 0xe3, 0xf4, 0x70, 0x43, 0x08, 0xd2, 0x5d, 0xcd, 0xd1, 0xe8, 0x4a, 0x16, 0x15, 0xfa, - 0x4c, 0xfa, 0x4c, 0xcd, 0xe9, 0xf3, 0xf5, 0xa1, 0xcf, 0xe8, 0x3a, 0x64, 0xb9, 0xd8, 0x14, 0x15, - 0xcb, 0x5b, 0x68, 0x0b, 0x32, 0xa6, 0x65, 0x4c, 0x30, 0xdd, 0xba, 0xbc, 0xc2, 0x1a, 0xb2, 0x02, - 0xe5, 0xf0, 0x41, 0x88, 0xca, 0x90, 0x74, 0xa6, 0x7c, 0x94, 0xa4, 0x33, 0x45, 0xdf, 0x85, 0x34, - 0x59, 0x48, 0x3a, 0x46, 0x39, 0xe2, 0xe8, 0xe7, 0x7c, 0xed, 0x2b, 0x13, 0x2b, 0x94, 0x52, 0xae, - 0x40, 0x29, 0x74, 0x40, 0xca, 0xd7, 0x61, 0x2b, 0xea, 0xbc, 0x93, 0xfb, 0x5e, 0x7f, 0xe8, 0xdc, - 0x42, 0x6f, 0x41, 0xde, 0x3b, 0xf0, 0x98, 0xe2, 0xdc, 0x9c, 0x1b, 0xd6, 0x25, 0x56, 0x3c, 0x52, - 0xa2, 0x31, 0x64, 0x03, 0xfa, 0x1a, 0x0f, 0x6f, 0x8a, 0x4a, 0x4e, 0x33, 0xcd, 0x96, 0x66, 0xf7, - 0xe5, 0x1f, 0x41, 0x35, 0xee, 0x30, 0x0b, 0x2c, 0x98, 0x40, 0xd5, 0xde, 0x5d, 0xb0, 0xeb, 0x90, - 0xbd, 0x34, 0xac, 0xa1, 0xe6, 0x50, 0x61, 0x25, 0x85, 0xb7, 0xc8, 0x42, 0xb2, 0x83, 0x2d, 0x45, - 0xbb, 0x59, 0x43, 0x56, 0xe1, 0x66, 0xec, 0x81, 0x46, 0x58, 0xf4, 0x51, 0x17, 0xb3, 0x65, 0x2d, - 0x29, 0xac, 0xe1, 0x0b, 0x62, 0x1f, 0xcb, 0x1a, 0x64, 0x58, 0x9b, 0xce, 0x95, 0xca, 0x17, 0x15, - 0xde, 0x92, 0xff, 0x2d, 0x0b, 0xd7, 0xa3, 0x8f, 0x35, 0x74, 0x17, 0x8a, 0x43, 0x6d, 0xaa, 0x3a, - 0x53, 0xae, 0x76, 0x02, 0xdd, 0x78, 0x18, 0x6a, 0xd3, 0xf6, 0x94, 0xe9, 0x9c, 0x04, 0x29, 0x67, - 0x6a, 0x57, 0x93, 0x77, 0x53, 0xf7, 0x8b, 0x0a, 0x79, 0x44, 0x67, 0xb0, 0x31, 0x30, 0x3a, 0xda, - 0x40, 0x1d, 0x68, 0xb6, 0xa3, 0xf2, 0x78, 0x87, 0x19, 0xd1, 0xcb, 0x73, 0x8b, 0xcd, 0x0e, 0x28, - 0xdc, 0x65, 0xfb, 0x49, 0x1c, 0x0e, 0xd7, 0xff, 0x0a, 0x95, 0x71, 0xa8, 0xb9, 0x5b, 0x8d, 0xce, - 0x60, 0xeb, 0xe2, 0xea, 0x73, 0x6d, 0xe4, 0xe8, 0x23, 0xac, 0xce, 0x99, 0xd5, 0xbc, 0xf6, 0x7c, - 0xa8, 0xdb, 0x17, 0xb8, 0xaf, 0x4d, 0x74, 0xc3, 0xe2, 0x22, 0x37, 0x3d, 0xfe, 0x73, 0xdf, 0xb6, - 0xfc, 0x3d, 0xca, 0x84, 0x94, 0xda, 0x75, 0x2f, 0xd9, 0xb5, 0xdd, 0xcb, 0x77, 0x61, 0x6b, 0x84, - 0xa7, 0x4e, 0xe0, 0x1b, 0x99, 0xe2, 0xe4, 0xe8, 0x5e, 0x20, 0xf2, 0xce, 0x1f, 0x9f, 0xe8, 0x10, - 0x7a, 0x8d, 0x46, 0x0a, 0xa6, 0x61, 0x63, 0x4b, 0xd5, 0xba, 0x5d, 0x0b, 0xdb, 0x76, 0x35, 0x4f, - 0xa9, 0x2b, 0x6e, 0x7f, 0x9d, 0x75, 0x87, 0x34, 0x51, 0x0c, 0x69, 0x22, 0x7a, 0x15, 0x2a, 0xb3, - 0x43, 0x02, 0xa5, 0x28, 0x4f, 0xc2, 0xc3, 0xdd, 0x83, 0xb2, 0xef, 0xe4, 0x28, 0x5d, 0x81, 0x79, - 0x13, 0xaf, 0x97, 0x92, 0xdd, 0x02, 0x91, 0xb8, 0x02, 0x46, 0x51, 0xa4, 0x14, 0x79, 0xd2, 0x41, - 0x5f, 0xbe, 0x0c, 0x25, 0x3c, 0xd1, 0xbb, 0x78, 0xd4, 0xc1, 0x8c, 0xa0, 0x44, 0x09, 0x8a, 0x6e, - 0x27, 0x25, 0x7a, 0x05, 0x2a, 0x54, 0x07, 0xd8, 0x29, 0x41, 0xc9, 0xca, 0x6c, 0x24, 0xd2, 0xcd, - 0x4e, 0x45, 0x42, 0xf7, 0x10, 0x6e, 0x06, 0xe8, 0x4c, 0xcd, 0x72, 0x54, 0x1b, 0x3b, 0xaa, 0x63, - 0x38, 0x3c, 0x10, 0x4b, 0x29, 0xd7, 0x3c, 0x8e, 0x13, 0xcd, 0x72, 0x4e, 0xb1, 0xd3, 0x26, 0x2f, - 0xd1, 0xdb, 0x50, 0x8d, 0xe2, 0xa4, 0x43, 0x49, 0x74, 0xa8, 0xad, 0x59, 0x46, 0x3a, 0xe2, 0x7d, - 0x90, 0x02, 0xda, 0xc9, 0xe8, 0x37, 0xd8, 0x62, 0x0d, 0x3c, 0x95, 0xa3, 0x94, 0x0f, 0x60, 0x83, - 0x52, 0x5a, 0xd8, 0x1e, 0x0f, 0x1c, 0xbe, 0x5e, 0x88, 0x6d, 0x0e, 0x79, 0xa1, 0xb0, 0x7e, 0xea, - 0x0b, 0xfe, 0x31, 0x68, 0x48, 0xe1, 0xb0, 0x8d, 0x9b, 0x89, 0xe0, 0x9b, 0xc9, 0x29, 0x6c, 0xf1, - 0xcd, 0xed, 0x86, 0x2c, 0x85, 0xa5, 0x4f, 0xb7, 0xe6, 0xbd, 0xe1, 0xac, 0x85, 0x20, 0x97, 0x7d, - 0x05, 0x23, 0x49, 0x3d, 0x9b, 0x91, 0x20, 0x48, 0xd3, 0x79, 0xa7, 0xd9, 0x09, 0x41, 0x9e, 0xbf, - 0xc9, 0x86, 0x03, 0x4b, 0x0d, 0xa7, 0xb0, 0xa2, 0xe1, 0x14, 0x97, 0x1a, 0x4e, 0x69, 0x99, 0xe1, - 0x94, 0x57, 0x33, 0x9c, 0xca, 0xda, 0x86, 0x23, 0x7d, 0x5d, 0xc3, 0xd9, 0x58, 0xd3, 0x70, 0xd0, - 0xea, 0x86, 0xb3, 0x19, 0x6d, 0x38, 0xef, 0xc3, 0xc6, 0x5c, 0xc2, 0xe2, 0x29, 0x9d, 0x10, 0xa9, - 0x74, 0xc9, 0xa0, 0xd2, 0xc9, 0x7f, 0x27, 0x40, 0x2d, 0x3e, 0x43, 0x89, 0x14, 0xf5, 0x3a, 0x6c, - 0x78, 0xdb, 0xeb, 0x29, 0x0f, 0x3b, 0x2f, 0x25, 0xef, 0x85, 0xab, 0x3d, 0x71, 0xa1, 0xcf, 0x3d, - 0x28, 0xcf, 0xe4, 0x4f, 0xcc, 0x44, 0x4a, 0x93, 0xe0, 0xf8, 0xf2, 0x3f, 0x64, 0xbd, 0x78, 0x24, - 0x94, 0xe4, 0x44, 0xb8, 0x85, 0x8f, 0x60, 0xb3, 0x8b, 0x3b, 0x7a, 0xf7, 0xeb, 0x7a, 0x85, 0x0d, - 0xce, 0xfd, 0xad, 0x53, 0xf8, 0xd6, 0x29, 0x7c, 0xb3, 0x9d, 0xc2, 0x5f, 0x25, 0x3d, 0xaf, 0xe0, - 0x27, 0xf3, 0x91, 0xa6, 0xfc, 0x36, 0xd1, 0x3a, 0x8d, 0x04, 0xb6, 0xcc, 0x4c, 0xaa, 0xf3, 0xb9, - 0x5a, 0x8b, 0xbe, 0xe7, 0xea, 0xcc, 0xa9, 0xd1, 0x71, 0xf8, 0xbb, 0x03, 0x38, 0xe4, 0x3c, 0xa8, - 0xe7, 0xdb, 0x53, 0xc0, 0xd8, 0x02, 0xd3, 0xa3, 0xb9, 0xb2, 0xb2, 0x30, 0x46, 0x9d, 0x4f, 0x35, - 0x9a, 0x7c, 0x7f, 0x17, 0x98, 0x99, 0xdc, 0xf4, 0x72, 0x5f, 0x0f, 0x8c, 0x98, 0xcb, 0xa4, 0x5e, - 0x82, 0xa2, 0xad, 0xf7, 0x54, 0x8a, 0xc2, 0xe8, 0x98, 0x65, 0xb5, 0x79, 0xa5, 0x60, 0xeb, 0xbd, - 0x73, 0xde, 0x25, 0xbf, 0x06, 0x95, 0x19, 0x40, 0x62, 0x26, 0x3d, 0xf1, 0x9d, 0xe9, 0xa6, 0xb7, - 0xee, 0x3e, 0xf0, 0x20, 0xff, 0xbc, 0x08, 0x79, 0x05, 0xdb, 0x26, 0x51, 0x6a, 0xb4, 0x07, 0x22, - 0x9e, 0x76, 0xb0, 0xe9, 0xb8, 0xa8, 0x40, 0x34, 0x78, 0xc1, 0xa8, 0x9b, 0x2e, 0x65, 0x2b, 0xa1, - 0xf8, 0x6c, 0xe8, 0x4d, 0x8e, 0x31, 0xc7, 0xc3, 0xc5, 0x9c, 0x3d, 0x08, 0x32, 0xbf, 0xed, 0x82, - 0xcc, 0xa9, 0x58, 0xfc, 0x94, 0x71, 0xcd, 0xa0, 0xcc, 0x6f, 0x72, 0x94, 0x39, 0xbd, 0x64, 0xb0, - 0x10, 0xcc, 0xdc, 0x08, 0xc1, 0xcc, 0x99, 0x25, 0xd3, 0x8c, 0xc1, 0x99, 0xdf, 0x76, 0x71, 0xe6, - 0xec, 0x92, 0x2f, 0x9e, 0x01, 0x9a, 0x7f, 0x10, 0x00, 0x9a, 0xf3, 0xb1, 0x08, 0x13, 0x63, 0x8d, - 0x40, 0x9a, 0xdf, 0xf1, 0x90, 0xe6, 0x42, 0x2c, 0x4a, 0xcd, 0x99, 0x67, 0xa1, 0xe6, 0xe3, 0x39, - 0xa8, 0x99, 0x41, 0xc3, 0xaf, 0xc4, 0x8a, 0x58, 0x82, 0x35, 0x1f, 0xcf, 0x61, 0xcd, 0xa5, 0x25, - 0x02, 0x97, 0x80, 0xcd, 0x7f, 0x16, 0x0d, 0x36, 0xc7, 0xc3, 0xc1, 0xfc, 0x33, 0x57, 0x43, 0x9b, - 0xd5, 0x18, 0xb4, 0xb9, 0x12, 0x8b, 0x8c, 0x32, 0xf1, 0x2b, 0xc3, 0xcd, 0x67, 0x11, 0x70, 0x33, - 0x03, 0x86, 0xef, 0xc7, 0x0a, 0x5f, 0x01, 0x6f, 0x3e, 0x8b, 0xc0, 0x9b, 0x37, 0x96, 0x8a, 0x5d, - 0x0a, 0x38, 0xef, 0x87, 0x01, 0x67, 0x14, 0x93, 0xc8, 0xfb, 0xd6, 0x1e, 0x83, 0x38, 0x5f, 0xc4, - 0x21, 0xce, 0x0c, 0x15, 0x7e, 0x23, 0x56, 0xe2, 0x1a, 0x90, 0xf3, 0xf1, 0x1c, 0xe4, 0xbc, 0xb5, - 0x44, 0xd3, 0x96, 0x60, 0xce, 0xfb, 0x61, 0xcc, 0xf9, 0xda, 0x92, 0xc9, 0xc7, 0x82, 0xce, 0x8d, - 0x10, 0xe8, 0x7c, 0x7d, 0x89, 0x2b, 0x89, 0x41, 0x9d, 0xff, 0x28, 0x88, 0x3a, 0xdf, 0x88, 0x05, - 0xae, 0xf9, 0x3e, 0x44, 0xc1, 0xce, 0xfb, 0x61, 0xd8, 0xb9, 0xba, 0x64, 0x3a, 0xab, 0xe0, 0xce, - 0x39, 0x29, 0xcf, 0x10, 0xe7, 0xc7, 0xe9, 0x3c, 0x48, 0x05, 0xf9, 0x35, 0x72, 0x78, 0xcc, 0x38, - 0x7e, 0xb4, 0x05, 0x19, 0x6c, 0x59, 0x86, 0xc5, 0x11, 0x64, 0xd6, 0x90, 0xef, 0x43, 0x31, 0xe8, - 0xe4, 0x17, 0x60, 0xd4, 0x14, 0xf7, 0x0b, 0x38, 0x76, 0xf9, 0x7f, 0x04, 0x9f, 0x97, 0x9e, 0xbc, - 0x41, 0x0c, 0x53, 0xe4, 0x18, 0x66, 0x00, 0xb9, 0x4e, 0x86, 0x91, 0xeb, 0x3b, 0x50, 0x20, 0x71, - 0xdf, 0x0c, 0x28, 0xad, 0x99, 0x1e, 0x28, 0xed, 0xc6, 0x29, 0x3c, 0xd6, 0x62, 0xa7, 0x64, 0x9a, - 0x9e, 0x92, 0x15, 0x3f, 0xda, 0x62, 0xb1, 0xed, 0x77, 0x60, 0x33, 0x40, 0xeb, 0xc5, 0x93, 0x0c, - 0xa1, 0x95, 0x3c, 0xea, 0x3a, 0x0f, 0x2c, 0xdf, 0x00, 0x34, 0xd4, 0x47, 0xfa, 0x70, 0x3c, 0x54, - 0x7b, 0x1a, 0x31, 0x55, 0xbd, 0x83, 0x6d, 0x7a, 0x3a, 0x88, 0x8a, 0xc4, 0xdf, 0x7c, 0xa0, 0xd9, - 0x27, 0xb4, 0x5f, 0xfe, 0x57, 0xc1, 0x5f, 0x4f, 0x1f, 0xfb, 0x8e, 0x82, 0xa9, 0x85, 0xe7, 0x04, - 0x53, 0x27, 0xbf, 0x36, 0x4c, 0x1d, 0x8c, 0xa6, 0x53, 0x61, 0x94, 0xf4, 0x7f, 0x05, 0x7f, 0x07, - 0x3d, 0xd0, 0xb9, 0x63, 0x74, 0x31, 0xc7, 0x2d, 0xe9, 0x33, 0xc9, 0x86, 0x06, 0x46, 0x8f, 0xa3, - 0x93, 0xe4, 0x91, 0x50, 0x79, 0xe7, 0xb6, 0xc8, 0x8f, 0x65, 0x0f, 0xf2, 0x64, 0x29, 0x06, 0x87, - 0x3c, 0x25, 0x48, 0x3d, 0xc5, 0xec, 0x94, 0x2d, 0x2a, 0xe4, 0x91, 0xd0, 0x51, 0x25, 0xe5, 0xa9, - 0x02, 0x6b, 0xa0, 0x87, 0x20, 0xd2, 0x3a, 0xbc, 0x6a, 0x98, 0x36, 0x3f, 0x58, 0x43, 0x59, 0x15, - 0x2b, 0xc6, 0x6f, 0x9f, 0x10, 0x9a, 0x63, 0xd3, 0x56, 0xf2, 0x26, 0x7f, 0x0a, 0x84, 0x4b, 0x62, - 0x28, 0xb7, 0x79, 0x01, 0x44, 0xf2, 0xf5, 0xb6, 0xa9, 0x75, 0x30, 0xcd, 0x22, 0x44, 0xc5, 0xef, - 0x90, 0x3f, 0x05, 0x34, 0xef, 0x1d, 0x50, 0x0b, 0xb2, 0x78, 0x82, 0x47, 0x0e, 0x4b, 0xfd, 0x0a, - 0xbb, 0xd7, 0x23, 0x42, 0x43, 0x3c, 0x72, 0xf6, 0xaa, 0x64, 0x91, 0x7f, 0xf3, 0xeb, 0x3b, 0x12, - 0xa3, 0x7e, 0xc3, 0x18, 0xea, 0x0e, 0x1e, 0x9a, 0xce, 0x95, 0xc2, 0xf9, 0xe5, 0x7f, 0x17, 0x48, - 0x60, 0x17, 0x8a, 0x03, 0x22, 0xd7, 0xd6, 0x35, 0x90, 0x64, 0x00, 0xe4, 0x9f, 0x5f, 0xef, 0x17, - 0x01, 0x88, 0x52, 0x7e, 0xa6, 0x8d, 0x1c, 0xdc, 0xe5, 0x0b, 0x2c, 0xf6, 0x34, 0xfb, 0x63, 0xda, - 0x11, 0x9e, 0x6a, 0x7e, 0x66, 0xaa, 0x01, 0x7c, 0x59, 0x0c, 0xe2, 0xcb, 0xa8, 0x06, 0x79, 0xd3, - 0xd2, 0x0d, 0x4b, 0x77, 0xae, 0xe8, 0xfa, 0xa4, 0x14, 0xaf, 0xfd, 0x38, 0x9d, 0x4f, 0x4b, 0x19, - 0xaf, 0x7c, 0xc5, 0x9c, 0x49, 0x41, 0x2a, 0xca, 0xff, 0x92, 0xf4, 0xf5, 0xde, 0x8f, 0x7b, 0xbf, - 0xfe, 0xc4, 0xa2, 0x14, 0xe9, 0x76, 0xc4, 0x64, 0x03, 0x3d, 0xe4, 0xbb, 0x49, 0x6b, 0x6c, 0xe3, - 0x2e, 0x2f, 0xa4, 0x78, 0xed, 0xc0, 0x06, 0xe6, 0x9e, 0x6d, 0x03, 0x97, 0xac, 0xe9, 0xf7, 0xa1, - 0x80, 0x27, 0x43, 0xd5, 0x99, 0xb2, 0xec, 0x44, 0xe4, 0xf9, 0xf3, 0xfc, 0x60, 0xc3, 0xf6, 0x94, - 0x38, 0x42, 0x45, 0xc4, 0xee, 0xa3, 0xfc, 0x37, 0xb4, 0x6c, 0x16, 0x3e, 0x0e, 0xd0, 0x69, 0x10, - 0xf6, 0x18, 0x53, 0x53, 0x76, 0x95, 0x70, 0x55, 0x9b, 0xf7, 0xe1, 0x11, 0xd6, 0x6d, 0xa3, 0x3f, - 0x86, 0x1b, 0x33, 0xfe, 0xc8, 0x13, 0x9d, 0x8c, 0x89, 0x5d, 0x67, 0xbd, 0xd2, 0xb5, 0xb0, 0x57, - 0x72, 0x25, 0xfb, 0xeb, 0x9c, 0x7a, 0x46, 0x43, 0x79, 0x0b, 0xca, 0xe1, 0x90, 0x97, 0x64, 0xdd, - 0x16, 0x76, 0x34, 0x7d, 0xa4, 0x86, 0xb0, 0x9d, 0x22, 0xeb, 0xe4, 0xc5, 0xb2, 0x13, 0xb8, 0x16, - 0x19, 0xe6, 0xa2, 0xef, 0x81, 0xe8, 0x47, 0xc8, 0x42, 0x4c, 0x82, 0xe7, 0xd5, 0x92, 0x7c, 0x5a, - 0xf9, 0x9f, 0x05, 0x5f, 0x64, 0xb8, 0x3a, 0xd5, 0x84, 0x2c, 0x4b, 0x8c, 0xa9, 0x82, 0x97, 0x77, - 0xbf, 0xb3, 0x5a, 0x80, 0xbc, 0xcd, 0xb2, 0x66, 0x85, 0x33, 0xcb, 0x9f, 0x42, 0x96, 0xf5, 0xa0, - 0x02, 0xe4, 0xce, 0x8e, 0x9e, 0x1c, 0x1d, 0x7f, 0x7c, 0x24, 0x25, 0x10, 0x40, 0xb6, 0xde, 0x68, - 0x34, 0x4f, 0xda, 0x92, 0x80, 0x44, 0xc8, 0xd4, 0xf7, 0x8e, 0x95, 0xb6, 0x94, 0x24, 0xdd, 0x4a, - 0xf3, 0x71, 0xb3, 0xd1, 0x96, 0x52, 0x68, 0x03, 0x4a, 0xec, 0x59, 0xdd, 0x3f, 0x56, 0x3e, 0xac, - 0xb7, 0xa5, 0x74, 0xa0, 0xeb, 0xb4, 0x79, 0xf4, 0xa8, 0xa9, 0x48, 0x19, 0xf9, 0xf7, 0xe1, 0x66, - 0x6c, 0x48, 0xed, 0x97, 0x9e, 0x84, 0x40, 0xe9, 0x49, 0xfe, 0xdb, 0x24, 0xd4, 0xe2, 0xe3, 0x64, - 0xf4, 0x78, 0x66, 0xe2, 0xbb, 0x6b, 0x04, 0xd9, 0x33, 0xb3, 0x47, 0xf7, 0xa0, 0x6c, 0xe1, 0x4b, - 0xec, 0x74, 0xfa, 0x2c, 0x6e, 0x67, 0x27, 0x5a, 0x49, 0x29, 0xf1, 0x5e, 0xca, 0x64, 0x33, 0xb2, - 0x1f, 0xe3, 0x8e, 0xa3, 0x32, 0x2f, 0xc5, 0x14, 0x4c, 0x24, 0x64, 0xa4, 0xf7, 0x94, 0x75, 0xca, - 0x3f, 0x5a, 0x6b, 0x2d, 0x45, 0xc8, 0x28, 0xcd, 0xb6, 0xf2, 0x89, 0x94, 0x42, 0x08, 0xca, 0xf4, - 0x51, 0x3d, 0x3d, 0xaa, 0x9f, 0x9c, 0xb6, 0x8e, 0xc9, 0x5a, 0x6e, 0x42, 0xc5, 0x5d, 0x4b, 0xb7, - 0x33, 0x23, 0xff, 0x47, 0x12, 0x6e, 0xc4, 0x44, 0xf9, 0xe8, 0x21, 0x80, 0x33, 0x55, 0x2d, 0xdc, - 0x31, 0xac, 0x6e, 0xbc, 0x92, 0xb5, 0xa7, 0x0a, 0xa5, 0x50, 0x44, 0x87, 0x3f, 0xd9, 0x0b, 0x2a, - 0x96, 0xe8, 0x3d, 0x2e, 0x94, 0x22, 0x2d, 0xdc, 0xac, 0x5e, 0x8c, 0x28, 0xcc, 0xe1, 0x0e, 0x11, - 0x4c, 0xd7, 0x96, 0x0a, 0xa6, 0xf4, 0xe8, 0xc3, 0x28, 0xff, 0xb1, 0x62, 0x69, 0x3b, 0xc2, 0x73, - 0x7c, 0x12, 0xef, 0x39, 0x32, 0xab, 0x06, 0x34, 0xd1, 0xae, 0x43, 0xfe, 0xfb, 0x54, 0x70, 0x61, - 0xc3, 0x49, 0xcd, 0x31, 0x64, 0x6d, 0x47, 0x73, 0xc6, 0x36, 0x57, 0xb8, 0xef, 0xad, 0x9a, 0x21, - 0x6d, 0xbb, 0x0f, 0xa7, 0x94, 0x5d, 0xe1, 0x62, 0xbe, 0x5d, 0x6f, 0xea, 0x60, 0xc3, 0x8b, 0x13, - 0x6f, 0x32, 0xbe, 0xcf, 0x49, 0xca, 0xef, 0xfa, 0x01, 0x52, 0x00, 0xfc, 0x9f, 0x07, 0xd6, 0x85, - 0x28, 0x60, 0xfd, 0xe7, 0x02, 0xdc, 0x5a, 0x90, 0x27, 0xa2, 0x8f, 0x66, 0xf6, 0xf9, 0x9d, 0x75, - 0xb2, 0xcc, 0x6d, 0xd6, 0x17, 0xde, 0x69, 0xf9, 0x4d, 0x28, 0x06, 0xfb, 0x57, 0x9b, 0xe4, 0x6f, - 0x92, 0xbe, 0xcf, 0x0f, 0x57, 0x00, 0x9e, 0x5b, 0x24, 0x38, 0xa3, 0x67, 0xc9, 0x35, 0xf5, 0x2c, - 0x32, 0x2e, 0x48, 0x3d, 0x63, 0x5c, 0xb0, 0x40, 0xdb, 0xd2, 0xcf, 0xa6, 0x6d, 0x21, 0x83, 0xcb, - 0x84, 0x93, 0x8d, 0x2d, 0x5f, 0xa3, 0x02, 0x00, 0xe6, 0x27, 0x00, 0x01, 0xa4, 0x76, 0x0b, 0x32, - 0x96, 0x31, 0x1e, 0x75, 0xa9, 0x5e, 0x64, 0x14, 0xd6, 0x40, 0x6f, 0x41, 0x86, 0xe8, 0x97, 0xbb, - 0x7a, 0xf3, 0xae, 0x96, 0xe8, 0x47, 0x00, 0xff, 0x65, 0xd4, 0xf2, 0x0f, 0xa1, 0x1c, 0x86, 0x87, - 0x9f, 0xaf, 0x78, 0x1d, 0xd0, 0xfc, 0x35, 0x89, 0x98, 0x21, 0x7e, 0x10, 0x1e, 0xe2, 0xa5, 0xd8, - 0x0b, 0x17, 0xd1, 0x43, 0x7d, 0x0e, 0x19, 0xaa, 0x6e, 0x24, 0x5e, 0xa6, 0x77, 0x73, 0x78, 0x3e, - 0x4d, 0x9e, 0xd1, 0x0f, 0x01, 0x34, 0xc7, 0xb1, 0xf4, 0x8b, 0xb1, 0x3f, 0xc0, 0x9d, 0x68, 0x75, - 0xad, 0xbb, 0x74, 0x7b, 0x2f, 0x70, 0xbd, 0xdd, 0xf2, 0x59, 0x03, 0xba, 0x1b, 0x10, 0x28, 0x1f, - 0x41, 0x39, 0xcc, 0xeb, 0xe6, 0x74, 0x42, 0x44, 0x4e, 0x97, 0x0c, 0xe6, 0x74, 0x5e, 0x46, 0x98, - 0x62, 0x17, 0x90, 0x68, 0x43, 0xfe, 0xa7, 0x24, 0x14, 0x83, 0xda, 0xfe, 0x9c, 0xb3, 0x87, 0x25, - 0xa9, 0xd2, 0xcd, 0xb9, 0xe4, 0x21, 0xd7, 0xd3, 0xec, 0xb3, 0x6f, 0x4a, 0xee, 0xf0, 0xd7, 0x02, - 0xe4, 0xbd, 0x85, 0x8b, 0x29, 0x14, 0xf8, 0xeb, 0x9e, 0x0c, 0x5e, 0x3e, 0x62, 0xc5, 0x89, 0x94, - 0x57, 0x9c, 0x78, 0xd7, 0x0b, 0xee, 0xe2, 0xd0, 0xf7, 0xe0, 0x2e, 0xb9, 0x25, 0x1a, 0x1e, 0xcb, - 0x5a, 0xec, 0x33, 0x48, 0x50, 0x83, 0xbe, 0x0f, 0x59, 0xad, 0xe3, 0x95, 0x1c, 0xca, 0x11, 0x00, - 0x9a, 0x4b, 0xba, 0xdd, 0x9e, 0xd6, 0x29, 0xa5, 0xc2, 0x39, 0xf8, 0x47, 0x25, 0xdd, 0x8f, 0x92, - 0x6b, 0x44, 0x6e, 0xdd, 0x7d, 0x07, 0x67, 0x47, 0x1f, 0x1e, 0x3f, 0x3a, 0xd8, 0x3f, 0x68, 0x3e, - 0x92, 0x12, 0x72, 0x03, 0x0a, 0x6e, 0x89, 0x4b, 0x1b, 0xda, 0xe8, 0x16, 0x88, 0x43, 0x2d, 0x7c, - 0x01, 0x2a, 0x3f, 0xd4, 0xf8, 0xf5, 0xa7, 0x1b, 0x90, 0x23, 0x2f, 0x7b, 0x9a, 0xed, 0x56, 0xa4, - 0x87, 0xda, 0xf4, 0x03, 0xcd, 0x96, 0x7f, 0x2b, 0x40, 0x65, 0xc6, 0x95, 0xa1, 0x5d, 0xc8, 0x30, - 0xf0, 0x2e, 0xee, 0x5e, 0x7d, 0x60, 0x58, 0x85, 0x91, 0xa2, 0xf7, 0x20, 0xef, 0x56, 0x01, 0xa3, - 0x72, 0x29, 0xe6, 0x33, 0xdd, 0x3a, 0x12, 0x67, 0xf5, 0x38, 0xd0, 0xfb, 0x20, 0x7a, 0x4e, 0x39, - 0xfe, 0x22, 0xa3, 0xe7, 0xce, 0x39, 0xbf, 0xcf, 0x83, 0xde, 0xf1, 0x31, 0xb4, 0xf4, 0x7c, 0x21, - 0x81, 0xb3, 0x33, 0x02, 0xce, 0xec, 0xd2, 0xcb, 0xef, 0x82, 0xe8, 0x09, 0x46, 0x55, 0xc8, 0xb9, - 0xb5, 0x58, 0x81, 0x7b, 0x6b, 0x5e, 0x83, 0xdd, 0x82, 0x8c, 0x69, 0x7c, 0xc6, 0x2f, 0xa5, 0xa5, - 0x14, 0xd6, 0x90, 0xbb, 0x50, 0x99, 0x39, 0x64, 0xd0, 0xbb, 0x90, 0x33, 0xc7, 0x17, 0xaa, 0xeb, - 0x11, 0x66, 0xd6, 0xcf, 0xc5, 0x6d, 0xc6, 0x17, 0x03, 0xbd, 0xf3, 0x04, 0x5f, 0xb9, 0x7a, 0x64, - 0x8e, 0x2f, 0x9e, 0x30, 0xc7, 0xc1, 0x46, 0x49, 0x06, 0x47, 0x99, 0x40, 0xde, 0xf5, 0x83, 0xe8, - 0x0f, 0x83, 0x4b, 0x25, 0xc4, 0xd8, 0x8a, 0xf7, 0x4d, 0x5c, 0x7c, 0x60, 0xa5, 0x1e, 0xc0, 0x86, - 0xad, 0xf7, 0x46, 0x6e, 0xdd, 0x9e, 0x6d, 0x34, 0x2b, 0xc4, 0x55, 0xd8, 0x8b, 0x43, 0x17, 0x0a, - 0x24, 0x61, 0x8b, 0x34, 0xeb, 0x88, 0xff, 0x3f, 0x3f, 0x20, 0x22, 0xbc, 0x4a, 0x45, 0x85, 0x57, - 0x7f, 0x99, 0x84, 0x42, 0xe0, 0x36, 0x00, 0xfa, 0x83, 0xc0, 0xa9, 0x50, 0x8e, 0x88, 0x0b, 0x02, - 0xb4, 0xfe, 0xad, 0xcd, 0xf0, 0xc4, 0x92, 0xeb, 0x4f, 0x2c, 0xee, 0xf2, 0x85, 0x7b, 0xa9, 0x20, - 0xbd, 0xf6, 0xa5, 0x82, 0x37, 0x00, 0xd1, 0x72, 0xb8, 0x3a, 0x31, 0x1c, 0x7d, 0xd4, 0x53, 0x99, - 0x6a, 0x30, 0x1f, 0x2e, 0xd1, 0x37, 0xe7, 0xf4, 0xc5, 0x09, 0xd5, 0x92, 0x3f, 0x4f, 0x42, 0xde, - 0xb5, 0xb0, 0xdf, 0xd1, 0x25, 0x50, 0x41, 0xf4, 0x8e, 0x09, 0xf4, 0x7b, 0x50, 0x62, 0x39, 0x73, - 0x3d, 0x60, 0xd1, 0xa2, 0x12, 0xee, 0x24, 0x16, 0x37, 0x32, 0x5c, 0xaf, 0x95, 0x56, 0x58, 0x83, - 0x4c, 0xc4, 0x99, 0xb6, 0x5c, 0x84, 0x58, 0x54, 0x78, 0x4b, 0xfe, 0x0b, 0x01, 0xf2, 0x1e, 0x0e, - 0xb2, 0xee, 0xbd, 0xd9, 0xeb, 0x90, 0xe5, 0xa9, 0x3e, 0xbb, 0x38, 0xcb, 0x5b, 0x91, 0x37, 0x54, - 0x6a, 0x90, 0x1f, 0x62, 0x47, 0xa3, 0x87, 0x3e, 0x8b, 0x1b, 0xbd, 0xf6, 0x83, 0x77, 0xa0, 0x10, - 0xb8, 0x73, 0x4c, 0xe2, 0x80, 0xa3, 0xe6, 0xc7, 0x52, 0xa2, 0x96, 0xfb, 0xe9, 0xcf, 0xee, 0xa6, - 0x8e, 0xf0, 0x67, 0xc4, 0x8b, 0x29, 0xcd, 0x46, 0xab, 0xd9, 0x78, 0x22, 0x09, 0xb5, 0xc2, 0x4f, - 0x7f, 0x76, 0x37, 0xa7, 0x60, 0x5a, 0x71, 0x7d, 0xf0, 0x04, 0x2a, 0x33, 0x3b, 0x1f, 0x4e, 0x0c, - 0x10, 0x94, 0x1f, 0x9d, 0x9d, 0x1c, 0x1e, 0x34, 0xea, 0xed, 0xa6, 0x7a, 0x7e, 0xdc, 0x6e, 0x4a, - 0x02, 0xba, 0x01, 0x9b, 0x87, 0x07, 0x1f, 0xb4, 0xda, 0x6a, 0xe3, 0xf0, 0xa0, 0x79, 0xd4, 0x56, - 0xeb, 0xed, 0x76, 0xbd, 0xf1, 0x44, 0x4a, 0xee, 0xfe, 0xb6, 0x00, 0x95, 0xfa, 0x5e, 0xe3, 0xa0, - 0x6e, 0x9a, 0x03, 0xbd, 0xa3, 0xd1, 0x43, 0xaa, 0x01, 0x69, 0x5a, 0x24, 0x59, 0xf8, 0x33, 0x56, - 0x6d, 0x71, 0x19, 0x1d, 0xed, 0x43, 0x86, 0xd6, 0x4f, 0xd0, 0xe2, 0xbf, 0xb3, 0x6a, 0x4b, 0xea, - 0xea, 0xe4, 0x63, 0xa8, 0x26, 0x2c, 0xfc, 0x5d, 0xab, 0xb6, 0xb8, 0xcc, 0x8e, 0x0e, 0x21, 0xe7, - 0x02, 0xd6, 0xcb, 0xfe, 0xa1, 0xaa, 0x2d, 0xad, 0x7d, 0x93, 0xa9, 0xb1, 0xc2, 0xc2, 0xe2, 0x3f, - 0xb9, 0x6a, 0x4b, 0x0a, 0xf0, 0xe8, 0x00, 0xb2, 0x1c, 0x1e, 0x5c, 0xf2, 0x73, 0x56, 0x6d, 0x59, - 0x49, 0x1d, 0x29, 0x20, 0xfa, 0x25, 0x9b, 0xe5, 0xff, 0xa7, 0xd5, 0x56, 0xb8, 0x5b, 0x80, 0x3e, - 0x85, 0x52, 0x18, 0x86, 0x5c, 0xed, 0x07, 0xb0, 0xda, 0x8a, 0xc5, 0x7b, 0x22, 0x3f, 0x8c, 0x49, - 0xae, 0xf6, 0x43, 0x58, 0x6d, 0xc5, 0x5a, 0x3e, 0xfa, 0x31, 0x6c, 0xcc, 0x63, 0x86, 0xab, 0xff, - 0x1f, 0x56, 0x5b, 0xa3, 0xba, 0x8f, 0x86, 0x80, 0x22, 0xb0, 0xc6, 0x35, 0x7e, 0x17, 0xab, 0xad, - 0x53, 0xec, 0x47, 0x5d, 0xa8, 0xcc, 0xe2, 0x77, 0xab, 0xfe, 0x3e, 0x56, 0x5b, 0xb9, 0xf0, 0xcf, - 0x46, 0x09, 0x83, 0x59, 0xab, 0xfe, 0x4e, 0x56, 0x5b, 0xf9, 0x1e, 0x00, 0x3a, 0x03, 0x08, 0x80, - 0x31, 0x2b, 0xfc, 0x5e, 0x56, 0x5b, 0xe5, 0x46, 0x00, 0x32, 0x61, 0x33, 0x0a, 0xa5, 0x59, 0xe7, - 0x6f, 0xb3, 0xda, 0x5a, 0x17, 0x05, 0x88, 0x3e, 0x87, 0xf1, 0x96, 0xd5, 0xfe, 0x3e, 0xab, 0xad, - 0x78, 0x63, 0x80, 0x2c, 0x94, 0x8f, 0x31, 0xa0, 0x15, 0xfe, 0xe0, 0xaa, 0xad, 0x52, 0x6e, 0xdf, - 0x6b, 0xfe, 0xe2, 0xcb, 0xdb, 0xc2, 0xaf, 0xbe, 0xbc, 0x2d, 0xfc, 0xf7, 0x97, 0xb7, 0x85, 0x2f, - 0xbe, 0xba, 0x9d, 0xf8, 0xd5, 0x57, 0xb7, 0x13, 0xff, 0xf9, 0xd5, 0xed, 0xc4, 0x9f, 0xbc, 0xde, - 0xd3, 0x9d, 0xfe, 0xf8, 0x62, 0xbb, 0x63, 0x0c, 0x77, 0x82, 0xbf, 0x01, 0x47, 0xfd, 0x9b, 0x7c, - 0x91, 0xa5, 0x81, 0xc0, 0x9b, 0xff, 0x17, 0x00, 0x00, 0xff, 0xff, 0x42, 0xc5, 0x78, 0x82, 0xbb, - 0x3c, 0x00, 0x00, + // 3885 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5b, 0x4b, 0x73, 0x1b, 0xd9, + 0x75, 0x46, 0xe3, 0x8d, 0x83, 0x57, 0xf3, 0x92, 0xa2, 0x20, 0x68, 0x86, 0xe4, 0xf4, 0x94, 0x66, + 0x34, 0x1a, 0x99, 0x74, 0xa8, 0x48, 0x96, 0xa2, 0x71, 0x26, 0x24, 0x04, 0x0e, 0x28, 0x51, 0x24, + 0xa7, 0x09, 0x72, 0x32, 0x49, 0xac, 0x76, 0x13, 0xb8, 0x04, 0xda, 0x02, 0xd0, 0xed, 0xee, 0x06, + 0x07, 0x9c, 0x55, 0x2a, 0x89, 0x37, 0xce, 0x66, 0x96, 0x59, 0xc4, 0xbb, 0xf8, 0x0f, 0x64, 0x91, + 0x65, 0x56, 0xa9, 0x94, 0x17, 0x5e, 0x78, 0x91, 0x4a, 0x65, 0xe5, 0xa4, 0x66, 0xaa, 0xb2, 0xf0, + 0x1f, 0xc8, 0x2e, 0x4e, 0xdd, 0x47, 0xbf, 0x80, 0x6e, 0x3c, 0x24, 0x95, 0xab, 0x5c, 0x99, 0x5d, + 0xdf, 0xdb, 0xe7, 0x9c, 0xfb, 0x3a, 0xaf, 0xfb, 0x9d, 0x6e, 0xb8, 0x69, 0xe3, 0x41, 0x1b, 0x9b, + 0x7d, 0x6d, 0x60, 0x6f, 0xa9, 0xe7, 0x2d, 0x6d, 0xcb, 0xbe, 0x32, 0xb0, 0xb5, 0x69, 0x98, 0xba, + 0xad, 0xa3, 0xb2, 0xf7, 0x72, 0x93, 0xbc, 0xac, 0xbe, 0xed, 0xa3, 0x6e, 0x99, 0x57, 0x86, 0xad, + 0x6f, 0x19, 0xa6, 0xae, 0x5f, 0x30, 0xfa, 0xea, 0x5b, 0x93, 0xaf, 0x5f, 0xe2, 0x2b, 0x2e, 0x2d, + 0xc0, 0x4c, 0x47, 0xd9, 0x32, 0x54, 0x53, 0xed, 0x5b, 0x21, 0xcc, 0xec, 0xb5, 0x6f, 0x2a, 0xd5, + 0xf5, 0x8e, 0xae, 0x77, 0x7a, 0x78, 0x8b, 0xb6, 0xce, 0x87, 0x17, 0x5b, 0xb6, 0xd6, 0xc7, 0x96, + 0xad, 0xf6, 0x0d, 0x4e, 0xb0, 0xd2, 0xd1, 0x3b, 0x3a, 0x7d, 0xdc, 0x22, 0x4f, 0xac, 0x57, 0xfa, + 0x65, 0x1e, 0x32, 0x32, 0xfe, 0xf1, 0x10, 0x5b, 0x36, 0xda, 0x86, 0x24, 0x6e, 0x75, 0xf5, 0x8a, + 0xb0, 0x21, 0xdc, 0xce, 0x6f, 0xbf, 0xb5, 0x39, 0xb6, 0xb8, 0x4d, 0x4e, 0x57, 0x6f, 0x75, 0xf5, + 0x46, 0x4c, 0xa6, 0xb4, 0xe8, 0x3e, 0xa4, 0x2e, 0x7a, 0x43, 0xab, 0x5b, 0x89, 0x53, 0xa6, 0xb7, + 0xa3, 0x98, 0xf6, 0x08, 0x51, 0x23, 0x26, 0x33, 0x6a, 0x32, 0x94, 0x36, 0xb8, 0xd0, 0x2b, 0x89, + 0xe9, 0x43, 0xed, 0x0f, 0x2e, 0xe8, 0x50, 0x84, 0x16, 0xed, 0x02, 0x68, 0x03, 0xcd, 0x56, 0x5a, + 0x5d, 0x55, 0x1b, 0x54, 0x92, 0x94, 0xf3, 0x9d, 0x68, 0x4e, 0xcd, 0xae, 0x11, 0xc2, 0x46, 0x4c, + 0xce, 0x69, 0x4e, 0x83, 0x4c, 0xf7, 0xc7, 0x43, 0x6c, 0x5e, 0x55, 0x52, 0xd3, 0xa7, 0xfb, 0x29, + 0x21, 0x22, 0xd3, 0xa5, 0xd4, 0xe8, 0x23, 0xc8, 0xb6, 0xba, 0xb8, 0xf5, 0x52, 0xb1, 0x47, 0x95, + 0x0c, 0xe5, 0x5c, 0x8f, 0xe2, 0xac, 0x11, 0xba, 0xe6, 0xa8, 0x11, 0x93, 0x33, 0x2d, 0xf6, 0x88, + 0x1e, 0x42, 0xba, 0xa5, 0xf7, 0xfb, 0x9a, 0x5d, 0x01, 0xca, 0xbb, 0x16, 0xc9, 0x4b, 0xa9, 0x1a, + 0x31, 0x99, 0xd3, 0xa3, 0x43, 0x28, 0xf5, 0x34, 0xcb, 0x56, 0xac, 0x81, 0x6a, 0x58, 0x5d, 0xdd, + 0xb6, 0x2a, 0x79, 0x2a, 0xe1, 0x56, 0x94, 0x84, 0x03, 0xcd, 0xb2, 0x4f, 0x1c, 0xe2, 0x46, 0x4c, + 0x2e, 0xf6, 0xfc, 0x1d, 0x44, 0x9e, 0x7e, 0x71, 0x81, 0x4d, 0x57, 0x60, 0xa5, 0x30, 0x5d, 0xde, + 0x11, 0xa1, 0x76, 0xf8, 0x89, 0x3c, 0xdd, 0xdf, 0x81, 0xfe, 0x1c, 0x96, 0x7b, 0xba, 0xda, 0x76, + 0xc5, 0x29, 0xad, 0xee, 0x70, 0xf0, 0xb2, 0x52, 0xa4, 0x42, 0x3f, 0x88, 0x9c, 0xa4, 0xae, 0xb6, + 0x1d, 0x11, 0x35, 0xc2, 0xd0, 0x88, 0xc9, 0x4b, 0xbd, 0xf1, 0x4e, 0xf4, 0x02, 0x56, 0x54, 0xc3, + 0xe8, 0x5d, 0x8d, 0x4b, 0x2f, 0x51, 0xe9, 0x77, 0xa2, 0xa4, 0xef, 0x10, 0x9e, 0x71, 0xf1, 0x48, + 0x9d, 0xe8, 0x45, 0x4d, 0x10, 0x0d, 0x13, 0x1b, 0xaa, 0x89, 0x15, 0xc3, 0xd4, 0x0d, 0xdd, 0x52, + 0x7b, 0x95, 0x32, 0x95, 0xfd, 0x7e, 0x94, 0xec, 0x63, 0x46, 0x7f, 0xcc, 0xc9, 0x1b, 0x31, 0xb9, + 0x6c, 0x04, 0xbb, 0x98, 0x54, 0xbd, 0x85, 0x2d, 0xcb, 0x93, 0x2a, 0xce, 0x92, 0x4a, 0xe9, 0x83, + 0x52, 0x03, 0x5d, 0xa8, 0x0e, 0x79, 0x3c, 0x22, 0xec, 0xca, 0xa5, 0x6e, 0xe3, 0xca, 0x12, 0x15, + 0x28, 0x45, 0x5a, 0x28, 0x25, 0x3d, 0xd3, 0x6d, 0xdc, 0x88, 0xc9, 0x80, 0xdd, 0x16, 0x52, 0xe1, + 0xda, 0x25, 0x36, 0xb5, 0x8b, 0x2b, 0x2a, 0x46, 0xa1, 0x6f, 0x2c, 0x4d, 0x1f, 0x54, 0x10, 0x15, + 0xf8, 0x61, 0x94, 0xc0, 0x33, 0xca, 0x44, 0x44, 0xd4, 0x1d, 0x96, 0x46, 0x4c, 0x5e, 0xbe, 0x9c, + 0xec, 0x26, 0x2a, 0x76, 0xa1, 0x0d, 0xd4, 0x9e, 0xf6, 0x25, 0x56, 0xce, 0x7b, 0x7a, 0xeb, 0x65, + 0x65, 0x79, 0xba, 0x8a, 0xed, 0x71, 0xea, 0x5d, 0x42, 0x4c, 0x54, 0xec, 0xc2, 0xdf, 0x41, 0x56, + 0x7e, 0x8e, 0x3b, 0xda, 0x80, 0x0b, 0x5b, 0x99, 0xbe, 0xf2, 0x5d, 0x42, 0xea, 0x48, 0x82, 0x73, + 0xb7, 0x45, 0x9c, 0x47, 0x1b, 0xf7, 0xb4, 0x4b, 0x6c, 0x12, 0x1b, 0xbe, 0x36, 0xdd, 0x79, 0x3c, + 0x61, 0x94, 0xd4, 0x8a, 0x73, 0x6d, 0xa7, 0x81, 0x3e, 0x86, 0x1c, 0x39, 0x01, 0x36, 0x91, 0x55, + 0x2a, 0x62, 0x23, 0xf2, 0x08, 0x06, 0x6d, 0x67, 0x1a, 0x59, 0xcc, 0x9f, 0xc9, 0x5a, 0xa8, 0xb9, + 0xf4, 0x54, 0x1b, 0x5b, 0x76, 0xe5, 0xfa, 0xf4, 0xb5, 0x10, 0x33, 0x39, 0xa0, 0x94, 0x64, 0x2d, + 0x3d, 0xb7, 0xb5, 0x9b, 0x81, 0xd4, 0xa5, 0xda, 0x1b, 0xe2, 0xa7, 0xc9, 0x6c, 0x5a, 0xcc, 0x3c, + 0x4d, 0x66, 0xb3, 0x62, 0xee, 0x69, 0x32, 0x9b, 0x13, 0x41, 0x7a, 0x1f, 0xf2, 0x3e, 0x2f, 0x8d, + 0x2a, 0x90, 0xe9, 0x63, 0xcb, 0x52, 0x3b, 0x98, 0x3a, 0xf5, 0x9c, 0xec, 0x34, 0xa5, 0x12, 0x14, + 0xfc, 0x9e, 0x59, 0xfa, 0x4a, 0x70, 0x39, 0x89, 0xd3, 0x25, 0x9c, 0x97, 0xd8, 0xa4, 0xba, 0xc1, + 0x39, 0x79, 0x13, 0xbd, 0x0b, 0x45, 0xba, 0x03, 0x8a, 0xf3, 0x9e, 0x78, 0xfe, 0xa4, 0x5c, 0xa0, + 0x9d, 0x67, 0x9c, 0x68, 0x1d, 0xf2, 0xc6, 0xb6, 0xe1, 0x92, 0x24, 0x28, 0x09, 0x18, 0xdb, 0x86, + 0x43, 0xf0, 0x0e, 0x14, 0xc8, 0x5a, 0x5d, 0x8a, 0x24, 0x1d, 0x24, 0x4f, 0xfa, 0x38, 0x89, 0xf4, + 0xcb, 0x38, 0x88, 0xe3, 0xde, 0x1c, 0x3d, 0x84, 0x24, 0x09, 0x6c, 0x3c, 0x46, 0x55, 0x37, 0x59, + 0xd4, 0xdb, 0x74, 0xa2, 0xde, 0x66, 0xd3, 0x89, 0x7a, 0xbb, 0xd9, 0x5f, 0xfc, 0x7a, 0x3d, 0xf6, + 0xd5, 0x7f, 0xae, 0x0b, 0x32, 0xe5, 0x40, 0x37, 0x88, 0x0f, 0x57, 0xb5, 0x81, 0xa2, 0xb5, 0xe9, + 0x94, 0x73, 0xc4, 0x41, 0xab, 0xda, 0x60, 0xbf, 0x8d, 0x0e, 0x40, 0x6c, 0xe9, 0x03, 0x0b, 0x0f, + 0xac, 0xa1, 0xa5, 0xb0, 0x98, 0xcb, 0x23, 0x53, 0x40, 0x45, 0x58, 0xb8, 0xad, 0x39, 0x94, 0xc7, + 0x94, 0x50, 0x2e, 0xb7, 0x82, 0x1d, 0x68, 0x0f, 0xe0, 0x52, 0xed, 0x69, 0x6d, 0xd5, 0xd6, 0x4d, + 0xab, 0x92, 0xdc, 0x48, 0x84, 0xea, 0xc9, 0x99, 0x43, 0x72, 0x6a, 0xb4, 0x55, 0x1b, 0xef, 0x26, + 0xc9, 0x74, 0x65, 0x1f, 0x27, 0x7a, 0x0f, 0xca, 0xaa, 0x61, 0x28, 0x96, 0xad, 0xda, 0x58, 0x39, + 0xbf, 0xb2, 0xb1, 0x45, 0xa3, 0x56, 0x41, 0x2e, 0xaa, 0x86, 0x71, 0x42, 0x7a, 0x77, 0x49, 0x27, + 0xba, 0x05, 0x25, 0x12, 0xe0, 0x34, 0xb5, 0xa7, 0x74, 0xb1, 0xd6, 0xe9, 0xda, 0x95, 0xf4, 0x86, + 0x70, 0x3b, 0x21, 0x17, 0x79, 0x6f, 0x83, 0x76, 0x4a, 0x6d, 0xf7, 0xc4, 0x69, 0x70, 0x43, 0x08, + 0x92, 0x6d, 0xd5, 0x56, 0xe9, 0x4e, 0x16, 0x64, 0xfa, 0x4c, 0xfa, 0x0c, 0xd5, 0xee, 0xf2, 0xfd, + 0xa1, 0xcf, 0x68, 0x15, 0xd2, 0x5c, 0x6c, 0x82, 0x8a, 0xe5, 0x2d, 0xb4, 0x02, 0x29, 0xc3, 0xd4, + 0x2f, 0x31, 0x3d, 0xba, 0xac, 0xcc, 0x1a, 0x92, 0x0c, 0xa5, 0x60, 0x20, 0x44, 0x25, 0x88, 0xdb, + 0x23, 0x3e, 0x4a, 0xdc, 0x1e, 0xa1, 0xef, 0x42, 0x92, 0x6c, 0x24, 0x1d, 0xa3, 0x14, 0x12, 0xfa, + 0x39, 0x5f, 0xf3, 0xca, 0xc0, 0x32, 0xa5, 0x94, 0xca, 0x50, 0x0c, 0x04, 0x48, 0x69, 0x15, 0x56, + 0xc2, 0xe2, 0x9d, 0xd4, 0x75, 0xfb, 0x03, 0x71, 0x0b, 0xdd, 0x87, 0xac, 0x1b, 0xf0, 0x98, 0xe2, + 0xdc, 0x98, 0x18, 0xd6, 0x21, 0x96, 0x5d, 0x52, 0xa2, 0x31, 0xe4, 0x00, 0xba, 0x2a, 0x4f, 0x6f, + 0x0a, 0x72, 0x46, 0x35, 0x8c, 0x86, 0x6a, 0x75, 0xa5, 0x1f, 0x42, 0x25, 0x2a, 0x98, 0xf9, 0x36, + 0x4c, 0xa0, 0x6a, 0xef, 0x6c, 0xd8, 0x2a, 0xa4, 0x2f, 0x74, 0xb3, 0xaf, 0xda, 0x54, 0x58, 0x51, + 0xe6, 0x2d, 0xb2, 0x91, 0x2c, 0xb0, 0x25, 0x68, 0x37, 0x6b, 0x48, 0x0a, 0xdc, 0x88, 0x0c, 0x68, + 0x84, 0x45, 0x1b, 0xb4, 0x31, 0xdb, 0xd6, 0xa2, 0xcc, 0x1a, 0x9e, 0x20, 0x36, 0x59, 0xd6, 0x20, + 0xc3, 0x5a, 0x74, 0xad, 0x54, 0x7e, 0x4e, 0xe6, 0x2d, 0xe9, 0x5f, 0xd3, 0xb0, 0x1a, 0x1e, 0xd6, + 0xd0, 0x06, 0x14, 0xfa, 0xea, 0x48, 0xb1, 0x47, 0x5c, 0xed, 0x04, 0x7a, 0xf0, 0xd0, 0x57, 0x47, + 0xcd, 0x11, 0xd3, 0x39, 0x11, 0x12, 0xf6, 0xc8, 0xaa, 0xc4, 0x37, 0x12, 0xb7, 0x0b, 0x32, 0x79, + 0x44, 0xa7, 0xb0, 0xd4, 0xd3, 0x5b, 0x6a, 0x4f, 0xe9, 0xa9, 0x96, 0xad, 0xf0, 0x7c, 0x87, 0x19, + 0xd1, 0xbb, 0x13, 0x9b, 0xcd, 0x02, 0x14, 0x6e, 0xb3, 0xf3, 0x24, 0x0e, 0x87, 0xeb, 0x7f, 0x99, + 0xca, 0x38, 0x50, 0x9d, 0xa3, 0x46, 0xa7, 0xb0, 0x72, 0x7e, 0xf5, 0xa5, 0x3a, 0xb0, 0xb5, 0x01, + 0x56, 0x26, 0xcc, 0x6a, 0x52, 0x7b, 0x9e, 0x6b, 0xd6, 0x39, 0xee, 0xaa, 0x97, 0x9a, 0x6e, 0x72, + 0x91, 0xcb, 0x2e, 0xff, 0x99, 0x67, 0x5b, 0xde, 0x19, 0xa5, 0x02, 0x4a, 0xed, 0xb8, 0x97, 0xf4, + 0xc2, 0xee, 0xe5, 0xbb, 0xb0, 0x32, 0xc0, 0x23, 0xdb, 0x37, 0x47, 0xa6, 0x38, 0x19, 0x7a, 0x16, + 0x88, 0xbc, 0xf3, 0xc6, 0x27, 0x3a, 0x84, 0x3e, 0xa0, 0x99, 0x82, 0xa1, 0x5b, 0xd8, 0x54, 0xd4, + 0x76, 0xdb, 0xc4, 0x96, 0x55, 0xc9, 0x52, 0xea, 0xb2, 0xd3, 0xbf, 0xc3, 0xba, 0x03, 0x9a, 0x98, + 0x0b, 0x68, 0x22, 0x7a, 0x1f, 0xca, 0xe3, 0x43, 0x02, 0xa5, 0x28, 0x5d, 0x06, 0x87, 0xbb, 0x05, + 0x25, 0xcf, 0xc9, 0x51, 0xba, 0x3c, 0xf3, 0x26, 0x6e, 0x2f, 0x25, 0xbb, 0x09, 0x39, 0xe2, 0x0a, + 0x18, 0x45, 0x81, 0x52, 0x64, 0x49, 0x07, 0x7d, 0xf9, 0x2e, 0x14, 0xf1, 0xa5, 0xd6, 0xc6, 0x83, + 0x16, 0x66, 0x04, 0x45, 0x4a, 0x50, 0x70, 0x3a, 0x29, 0xd1, 0x7b, 0x50, 0xa6, 0x3a, 0xc0, 0xa2, + 0x04, 0x25, 0x2b, 0xb1, 0x91, 0x48, 0x37, 0x8b, 0x8a, 0x84, 0xee, 0x21, 0xdc, 0xf0, 0xd1, 0x19, + 0xaa, 0x69, 0x2b, 0x16, 0xb6, 0x15, 0x5b, 0xb7, 0x79, 0x22, 0x96, 0x90, 0xaf, 0xb9, 0x1c, 0xc7, + 0xaa, 0x69, 0x9f, 0x60, 0xbb, 0x49, 0x5e, 0xa2, 0x07, 0x50, 0x09, 0xe3, 0xa4, 0x43, 0x89, 0x74, + 0xa8, 0x95, 0x71, 0x46, 0x3a, 0xe2, 0x6d, 0x10, 0x7d, 0xda, 0xc9, 0xe8, 0x97, 0xd8, 0x66, 0xf5, + 0x5c, 0x95, 0xa3, 0x94, 0x77, 0x60, 0x89, 0x52, 0x9a, 0xd8, 0x1a, 0xf6, 0x6c, 0xbe, 0x5f, 0x88, + 0x1d, 0x0e, 0x79, 0x21, 0xb3, 0x7e, 0xea, 0x0b, 0xfe, 0xc9, 0x6f, 0x48, 0xc1, 0xb4, 0x8d, 0x9b, + 0x89, 0xe0, 0x99, 0xc9, 0x09, 0xac, 0xf0, 0xc3, 0x6d, 0x07, 0x2c, 0x85, 0x5d, 0x9f, 0x6e, 0x4e, + 0x7a, 0xc3, 0x71, 0x0b, 0x41, 0x0e, 0xfb, 0x1c, 0x46, 0x92, 0x78, 0x3d, 0x23, 0x41, 0x90, 0xa4, + 0xeb, 0x4e, 0xb2, 0x08, 0x41, 0x9e, 0x7f, 0x9f, 0x0d, 0x07, 0x66, 0x1a, 0x4e, 0x7e, 0x4e, 0xc3, + 0x29, 0xcc, 0x34, 0x9c, 0xe2, 0x2c, 0xc3, 0x29, 0xcd, 0x67, 0x38, 0xe5, 0x85, 0x0d, 0x47, 0x7c, + 0x55, 0xc3, 0x59, 0x5a, 0xd0, 0x70, 0xd0, 0xfc, 0x86, 0xb3, 0x1c, 0x6e, 0x38, 0x1f, 0xc3, 0xd2, + 0xc4, 0x85, 0xc5, 0x55, 0x3a, 0x21, 0x54, 0xe9, 0xe2, 0x7e, 0xa5, 0x93, 0xfe, 0x5e, 0x80, 0x6a, + 0xf4, 0x0d, 0x25, 0x54, 0xd4, 0x87, 0xb0, 0xe4, 0x1e, 0xaf, 0xab, 0x3c, 0x2c, 0x5e, 0x8a, 0xee, + 0x0b, 0x47, 0x7b, 0xa2, 0x52, 0x9f, 0x5b, 0x50, 0x1a, 0xbb, 0x3f, 0x31, 0x13, 0x29, 0x5e, 0xfa, + 0xc7, 0x97, 0xfe, 0x31, 0xed, 0xe6, 0x23, 0x81, 0x4b, 0x4e, 0x88, 0x5b, 0xf8, 0x14, 0x96, 0xdb, + 0xb8, 0xa5, 0xb5, 0x5f, 0xd5, 0x2b, 0x2c, 0x71, 0xee, 0x6f, 0x9d, 0xc2, 0xb7, 0x4e, 0xe1, 0xf7, + 0xdb, 0x29, 0xfc, 0x4d, 0xdc, 0xf5, 0x0a, 0xde, 0x65, 0x3e, 0xd4, 0x94, 0x1f, 0x10, 0xad, 0x53, + 0x49, 0x62, 0xcb, 0xcc, 0xa4, 0x32, 0x79, 0x57, 0x6b, 0xd0, 0xf7, 0x5c, 0x9d, 0x39, 0x35, 0x3a, + 0x0a, 0xce, 0xdb, 0x87, 0x43, 0x4e, 0x82, 0x7a, 0x9e, 0x3d, 0xf9, 0x8c, 0xcd, 0xb7, 0x3c, 0x7a, + 0x57, 0x96, 0xa7, 0xe6, 0xa8, 0x93, 0x57, 0x8d, 0x3a, 0x3f, 0xdf, 0x29, 0x66, 0x26, 0xd5, 0xdd, + 0xbb, 0xaf, 0x0b, 0x46, 0x4c, 0xdc, 0xa4, 0xde, 0x81, 0x82, 0xa5, 0x75, 0x14, 0x8a, 0xc2, 0x68, + 0x98, 0xdd, 0x6a, 0xb3, 0x72, 0xde, 0xd2, 0x3a, 0x67, 0xbc, 0x4b, 0xfa, 0x00, 0xca, 0x63, 0x80, + 0xc4, 0xd8, 0xf5, 0xc4, 0x73, 0xa6, 0xcb, 0xee, 0xbe, 0x7b, 0xc0, 0x83, 0xf4, 0xf3, 0x02, 0x64, + 0x65, 0x6c, 0x19, 0x44, 0xa9, 0xd1, 0x2e, 0xe4, 0xf0, 0xa8, 0x85, 0x0d, 0xdb, 0x41, 0x05, 0xc2, + 0xc1, 0x0b, 0x46, 0x5d, 0x77, 0x28, 0x1b, 0x31, 0xd9, 0x63, 0x43, 0xf7, 0x38, 0xc6, 0x1c, 0x0d, + 0x17, 0x73, 0x76, 0x3f, 0xc8, 0xfc, 0xc0, 0x01, 0x99, 0x13, 0x91, 0xf8, 0x29, 0xe3, 0x1a, 0x43, + 0x99, 0xef, 0x71, 0x94, 0x39, 0x39, 0x63, 0xb0, 0x00, 0xcc, 0x5c, 0x0b, 0xc0, 0xcc, 0xa9, 0x19, + 0xcb, 0x8c, 0xc0, 0x99, 0x1f, 0x38, 0x38, 0x73, 0x7a, 0xc6, 0x8c, 0xc7, 0x80, 0xe6, 0xef, 0xfb, + 0x80, 0xe6, 0x6c, 0x24, 0xc2, 0xc4, 0x58, 0x43, 0x90, 0xe6, 0x47, 0x2e, 0xd2, 0x9c, 0x8f, 0x44, + 0xa9, 0x39, 0xf3, 0x38, 0xd4, 0x7c, 0x34, 0x01, 0x35, 0x33, 0x68, 0xf8, 0xbd, 0x48, 0x11, 0x33, + 0xb0, 0xe6, 0xa3, 0x09, 0xac, 0xb9, 0x38, 0x43, 0xe0, 0x0c, 0xb0, 0xf9, 0x2f, 0xc2, 0xc1, 0xe6, + 0x68, 0x38, 0x98, 0x4f, 0x73, 0x3e, 0xb4, 0x59, 0x89, 0x40, 0x9b, 0xcb, 0x91, 0xc8, 0x28, 0x13, + 0x3f, 0x37, 0xdc, 0x7c, 0x1a, 0x02, 0x37, 0x33, 0x60, 0xf8, 0x76, 0xa4, 0xf0, 0x39, 0xf0, 0xe6, + 0xd3, 0x10, 0xbc, 0x79, 0x69, 0xa6, 0xd8, 0x99, 0x80, 0xf3, 0x5e, 0x10, 0x70, 0x46, 0x11, 0x17, + 0x79, 0xcf, 0xda, 0x23, 0x10, 0xe7, 0xf3, 0x28, 0xc4, 0x99, 0xa1, 0xc2, 0x77, 0x23, 0x25, 0x2e, + 0x00, 0x39, 0x1f, 0x4d, 0x40, 0xce, 0x2b, 0x33, 0x34, 0x6d, 0x06, 0xe6, 0xbc, 0x17, 0xc4, 0x9c, + 0xaf, 0xcd, 0x58, 0x7c, 0x24, 0xe8, 0x5c, 0x0b, 0x80, 0xce, 0xab, 0x33, 0x5c, 0x49, 0x04, 0xea, + 0xfc, 0x27, 0x7e, 0xd4, 0xf9, 0x7a, 0x24, 0x70, 0xcd, 0xcf, 0x21, 0x0c, 0x76, 0xde, 0x0b, 0xc2, + 0xce, 0x95, 0x19, 0xcb, 0x99, 0x07, 0x77, 0xce, 0x88, 0x59, 0x86, 0x38, 0x3f, 0x4d, 0x66, 0x41, + 0xcc, 0x4b, 0x1f, 0x90, 0xe0, 0x31, 0xe6, 0xf8, 0xd1, 0x0a, 0xa4, 0xb0, 0x69, 0xea, 0x26, 0x47, + 0x90, 0x59, 0x43, 0xba, 0x0d, 0x05, 0xbf, 0x93, 0x9f, 0x82, 0x51, 0x53, 0xdc, 0xcf, 0xe7, 0xd8, + 0xa5, 0xff, 0x16, 0x3c, 0x5e, 0x1a, 0x79, 0xfd, 0x18, 0x66, 0x8e, 0x63, 0x98, 0x3e, 0xe4, 0x3a, + 0x1e, 0x44, 0xae, 0xd7, 0x21, 0x4f, 0xf2, 0xbe, 0x31, 0x50, 0x5a, 0x35, 0x5c, 0x50, 0xda, 0xc9, + 0x53, 0x78, 0xae, 0xc5, 0xa2, 0x64, 0x92, 0x46, 0xc9, 0xb2, 0x97, 0x6d, 0xb1, 0xdc, 0xf6, 0x3b, + 0xb0, 0xec, 0xa3, 0x75, 0xf3, 0x49, 0x86, 0xd0, 0x8a, 0x2e, 0xf5, 0x0e, 0x4f, 0x2c, 0xef, 0x02, + 0xea, 0x6b, 0x03, 0xad, 0x3f, 0xec, 0x2b, 0x1d, 0x95, 0x98, 0xaa, 0xd6, 0xc2, 0x16, 0x8d, 0x0e, + 0x39, 0x59, 0xe4, 0x6f, 0x3e, 0x51, 0xad, 0x63, 0xda, 0x2f, 0xfd, 0x8b, 0xe0, 0xed, 0xa7, 0x87, + 0x7d, 0x87, 0xc1, 0xd4, 0xc2, 0x1b, 0x82, 0xa9, 0xe3, 0xaf, 0x0c, 0x53, 0xfb, 0xb3, 0xe9, 0x44, + 0x10, 0x25, 0xfd, 0x1f, 0xc1, 0x3b, 0x41, 0x17, 0x74, 0x6e, 0xe9, 0x6d, 0xcc, 0x71, 0x4b, 0xfa, + 0x4c, 0x6e, 0x43, 0x3d, 0xbd, 0xc3, 0xd1, 0x49, 0xf2, 0x48, 0xa8, 0xdc, 0xb8, 0x9d, 0xe3, 0x61, + 0xd9, 0x85, 0x3c, 0xd9, 0x15, 0x83, 0x43, 0x9e, 0x22, 0x24, 0x5e, 0x62, 0x16, 0x65, 0x0b, 0x32, + 0x79, 0x24, 0x74, 0x54, 0x49, 0xf9, 0x55, 0x81, 0x35, 0xd0, 0x43, 0xc8, 0xd1, 0x3a, 0xbc, 0xa2, + 0x1b, 0x16, 0x0f, 0xac, 0x81, 0x5b, 0x15, 0x2b, 0xc6, 0x6f, 0x1e, 0x13, 0x9a, 0x23, 0xc3, 0x92, + 0xb3, 0x06, 0x7f, 0xf2, 0xa5, 0x4b, 0xb9, 0xc0, 0xdd, 0xe6, 0x2d, 0xc8, 0x91, 0xd9, 0x5b, 0x86, + 0xda, 0xc2, 0xf4, 0x16, 0x91, 0x93, 0xbd, 0x0e, 0xe9, 0x05, 0xa0, 0x49, 0xef, 0x80, 0x1a, 0x90, + 0xc6, 0x97, 0x78, 0x60, 0xb3, 0xab, 0x5f, 0x7e, 0x7b, 0x35, 0x24, 0x35, 0xc4, 0x03, 0x7b, 0xb7, + 0x42, 0x36, 0xf9, 0x37, 0xbf, 0x5e, 0x17, 0x19, 0xf5, 0x5d, 0xbd, 0xaf, 0xd9, 0xb8, 0x6f, 0xd8, + 0x57, 0x32, 0xe7, 0x97, 0xfe, 0x4d, 0x20, 0x89, 0x5d, 0x20, 0x0f, 0x08, 0xdd, 0x5b, 0xc7, 0x40, + 0xe2, 0x3e, 0x90, 0x7f, 0x72, 0xbf, 0xdf, 0x06, 0x20, 0x4a, 0xf9, 0x85, 0x3a, 0xb0, 0x71, 0x9b, + 0x6f, 0x70, 0xae, 0xa3, 0x5a, 0x9f, 0xd1, 0x8e, 0xe0, 0x52, 0xb3, 0x63, 0x4b, 0xf5, 0xe1, 0xcb, + 0x39, 0x3f, 0xbe, 0x8c, 0xaa, 0x90, 0x35, 0x4c, 0x4d, 0x37, 0x35, 0xfb, 0x8a, 0xee, 0x4f, 0x42, + 0x76, 0xdb, 0x4f, 0x93, 0xd9, 0xa4, 0x98, 0x72, 0xcb, 0x57, 0xcc, 0x99, 0xe4, 0xc5, 0x82, 0xf4, + 0x93, 0xb8, 0xa7, 0xf7, 0x5e, 0xde, 0xfb, 0xea, 0x0b, 0x0b, 0x53, 0xa4, 0xb5, 0x90, 0xc5, 0xfa, + 0x7a, 0xc8, 0xbc, 0x49, 0x6b, 0x68, 0xe1, 0x36, 0x2f, 0xa4, 0xb8, 0x6d, 0xdf, 0x01, 0x66, 0x5e, + 0xef, 0x00, 0xa7, 0xef, 0xa9, 0xf4, 0xb7, 0xb4, 0xf4, 0x15, 0x74, 0xe9, 0xe8, 0xc4, 0x0f, 0x5d, + 0x0c, 0xa9, 0x39, 0x3a, 0x8a, 0x34, 0xaf, 0xdd, 0x7a, 0x10, 0x07, 0xeb, 0xb6, 0xd0, 0x9f, 0xc2, + 0xf5, 0x31, 0x9f, 0xe2, 0x8a, 0x8e, 0x47, 0xe4, 0x9f, 0xe3, 0x9e, 0xe5, 0x5a, 0xd0, 0xb3, 0x38, + 0x92, 0xbd, 0xbd, 0x4a, 0xbc, 0xa6, 0xb2, 0xdf, 0x87, 0x52, 0x30, 0x6d, 0x25, 0x37, 0x67, 0x13, + 0xdb, 0xaa, 0x36, 0x50, 0x02, 0xf8, 0x4c, 0x81, 0x75, 0xf2, 0x82, 0xd7, 0x31, 0x5c, 0x0b, 0x4d, + 0x55, 0xd1, 0xf7, 0x20, 0xe7, 0x65, 0xb9, 0x42, 0xc4, 0x25, 0xcd, 0xad, 0x07, 0x79, 0xb4, 0xd2, + 0x3f, 0x0b, 0x9e, 0xc8, 0x60, 0x85, 0xa9, 0x0e, 0x69, 0x76, 0xb9, 0xa5, 0x4a, 0x5a, 0xda, 0xfe, + 0xce, 0x7c, 0x49, 0xee, 0x26, 0xbb, 0xf9, 0xca, 0x9c, 0x59, 0x7a, 0x01, 0x69, 0xd6, 0x83, 0xf2, + 0x90, 0x39, 0x3d, 0x7c, 0x76, 0x78, 0xf4, 0xd9, 0xa1, 0x18, 0x43, 0x00, 0xe9, 0x9d, 0x5a, 0xad, + 0x7e, 0xdc, 0x14, 0x05, 0x94, 0x83, 0xd4, 0xce, 0xee, 0x91, 0xdc, 0x14, 0xe3, 0xa4, 0x5b, 0xae, + 0x3f, 0xad, 0xd7, 0x9a, 0x62, 0x02, 0x2d, 0x41, 0x91, 0x3d, 0x2b, 0x7b, 0x47, 0xf2, 0xf3, 0x9d, + 0xa6, 0x98, 0xf4, 0x75, 0x9d, 0xd4, 0x0f, 0x9f, 0xd4, 0x65, 0x31, 0x25, 0xfd, 0x01, 0xdc, 0x88, + 0x4c, 0x8b, 0xbd, 0xf2, 0x91, 0xe0, 0x2b, 0x1f, 0x49, 0x7f, 0x17, 0x87, 0x6a, 0x74, 0xae, 0x8b, + 0x9e, 0x8e, 0x2d, 0x7c, 0x7b, 0x81, 0x44, 0x79, 0x6c, 0xf5, 0xe8, 0x16, 0x94, 0x4c, 0x7c, 0x81, + 0xed, 0x56, 0x97, 0xe5, 0xde, 0x2c, 0x2a, 0x15, 0xe5, 0x22, 0xef, 0xa5, 0x4c, 0x16, 0x23, 0xfb, + 0x11, 0x6e, 0xd9, 0x0a, 0xf3, 0x34, 0x4c, 0xc1, 0x72, 0x84, 0x8c, 0xf4, 0x9e, 0xb0, 0x4e, 0xe9, + 0x87, 0x0b, 0xed, 0x65, 0x0e, 0x52, 0x72, 0xbd, 0x29, 0x7f, 0x2e, 0x26, 0x10, 0x82, 0x12, 0x7d, + 0x54, 0x4e, 0x0e, 0x77, 0x8e, 0x4f, 0x1a, 0x47, 0x64, 0x2f, 0x97, 0xa1, 0xec, 0xec, 0xa5, 0xd3, + 0x99, 0x92, 0xfe, 0x3d, 0x0e, 0xd7, 0x23, 0x32, 0x75, 0xf4, 0x10, 0xc0, 0x1e, 0x29, 0x26, 0x6e, + 0xe9, 0x66, 0x3b, 0x5a, 0xc9, 0x9a, 0x23, 0x99, 0x52, 0xc8, 0x39, 0x9b, 0x3f, 0x59, 0x53, 0xaa, + 0x8e, 0xe8, 0x23, 0x2e, 0x94, 0xa2, 0x25, 0xdc, 0xac, 0xde, 0x0e, 0x29, 0xae, 0xe1, 0x16, 0x11, + 0x4c, 0xf7, 0x96, 0x0a, 0xa6, 0xf4, 0xe8, 0x79, 0x98, 0xff, 0x98, 0xb3, 0x3c, 0x1d, 0xe2, 0x39, + 0x3e, 0x8f, 0xf6, 0x1c, 0xa9, 0x79, 0x93, 0x92, 0x70, 0xd7, 0x21, 0xfd, 0x43, 0xc2, 0xbf, 0xb1, + 0xc1, 0x8b, 0xc9, 0x11, 0xa4, 0x2d, 0x5b, 0xb5, 0x87, 0x16, 0x57, 0xb8, 0xef, 0xcd, 0x7b, 0xcb, + 0xd9, 0x74, 0x1e, 0x4e, 0x28, 0xbb, 0xcc, 0xc5, 0x7c, 0xbb, 0xdf, 0xd4, 0xc1, 0x06, 0x37, 0x27, + 0xda, 0x64, 0x3c, 0x9f, 0x13, 0x97, 0x1e, 0x7b, 0x49, 0x8e, 0x0f, 0xc0, 0x9f, 0x04, 0xc7, 0x85, + 0x30, 0x70, 0xfc, 0xe7, 0x02, 0xdc, 0x9c, 0x72, 0xd7, 0x43, 0x9f, 0x8e, 0x9d, 0xf3, 0xa3, 0x45, + 0x6e, 0x8a, 0x9b, 0xac, 0x2f, 0x78, 0xd2, 0xd2, 0x3d, 0x28, 0xf8, 0xfb, 0xe7, 0x5b, 0xe4, 0x6f, + 0xe2, 0x9e, 0xcf, 0x0f, 0xa2, 0xf8, 0x6f, 0x2c, 0x9b, 0x1b, 0xd3, 0xb3, 0xf8, 0x82, 0x7a, 0x16, + 0x9a, 0x17, 0x24, 0x5e, 0x33, 0x2f, 0x98, 0xa2, 0x6d, 0xc9, 0xd7, 0xd3, 0xb6, 0x80, 0xc1, 0xa5, + 0x82, 0x17, 0x86, 0x15, 0x4f, 0xa3, 0x7c, 0x20, 0xe4, 0xe7, 0x00, 0x3e, 0xb4, 0x75, 0x05, 0x52, + 0xa6, 0x3e, 0x1c, 0xb4, 0xa9, 0x5e, 0xa4, 0x64, 0xd6, 0x40, 0xf7, 0x21, 0x45, 0xf4, 0xcb, 0xd9, + 0xbd, 0x49, 0x57, 0x4b, 0xf4, 0xc3, 0x87, 0xe1, 0x32, 0x6a, 0xe9, 0x07, 0x50, 0x0a, 0x42, 0xbc, + 0x6f, 0x56, 0xbc, 0x06, 0x68, 0xf2, 0x53, 0x87, 0x88, 0x21, 0xbe, 0x1f, 0x1c, 0xe2, 0x9d, 0xc8, + 0x8f, 0x26, 0xc2, 0x87, 0xfa, 0x12, 0x52, 0x54, 0xdd, 0x48, 0xce, 0x4b, 0xbf, 0xaf, 0xe1, 0x77, + 0x62, 0xf2, 0x8c, 0x7e, 0x00, 0xa0, 0xda, 0xb6, 0xa9, 0x9d, 0x0f, 0xbd, 0x01, 0xd6, 0xc3, 0xd5, + 0x75, 0xc7, 0xa1, 0xdb, 0x7d, 0x8b, 0xeb, 0xed, 0x8a, 0xc7, 0xea, 0xd3, 0x5d, 0x9f, 0x40, 0xe9, + 0x10, 0x4a, 0x41, 0x5e, 0xe7, 0x5e, 0x26, 0x84, 0xdc, 0xcb, 0xe2, 0xfe, 0x7b, 0x99, 0x7b, 0xab, + 0x4b, 0xb0, 0x8f, 0x88, 0x68, 0x43, 0xfa, 0x5f, 0x01, 0x0a, 0x7e, 0x6d, 0x7f, 0xc3, 0x37, 0x80, + 0x19, 0xd7, 0x9d, 0x1b, 0x13, 0x17, 0x80, 0x4c, 0x47, 0xb5, 0x4e, 0x7f, 0x97, 0xf9, 0xff, 0x4f, + 0x04, 0xc8, 0xba, 0x8b, 0x8f, 0x00, 0xec, 0xbd, 0xbd, 0x8b, 0xfb, 0x3f, 0x02, 0x62, 0x45, 0x82, + 0x84, 0x5b, 0x24, 0x78, 0xec, 0x26, 0x68, 0x51, 0x28, 0xb8, 0x7f, 0xa7, 0x9d, 0x52, 0x09, 0xcf, + 0x47, 0x4d, 0x36, 0x0d, 0x92, 0x98, 0xa0, 0x3f, 0x82, 0xb4, 0xda, 0x72, 0xa1, 0xff, 0x52, 0x08, + 0x90, 0xe5, 0x90, 0x6e, 0x36, 0x47, 0x3b, 0x94, 0x52, 0xe6, 0x1c, 0x7c, 0x52, 0x71, 0x67, 0x52, + 0x52, 0x95, 0xc8, 0xdd, 0x71, 0xde, 0xc1, 0xe9, 0xe1, 0xf3, 0xa3, 0x27, 0xfb, 0x7b, 0xfb, 0xf5, + 0x27, 0x62, 0x4c, 0xaa, 0x41, 0xde, 0x29, 0x35, 0xa9, 0x7d, 0x0b, 0xdd, 0x84, 0x5c, 0x5f, 0x0d, + 0x7e, 0x88, 0x94, 0xed, 0xab, 0xfc, 0x33, 0xa4, 0xeb, 0x90, 0x21, 0x2f, 0x3b, 0xaa, 0xe5, 0x54, + 0x86, 0xfb, 0xea, 0xe8, 0x13, 0xd5, 0x92, 0x7e, 0x2b, 0x40, 0x79, 0xcc, 0x1d, 0xa1, 0x6d, 0x48, + 0x31, 0x10, 0x2d, 0xea, 0xfb, 0x76, 0xdf, 0xb0, 0x32, 0x23, 0x45, 0x1f, 0x41, 0xd6, 0xa9, 0xc6, + 0x85, 0xdd, 0x87, 0x98, 0xdf, 0x73, 0xea, 0x39, 0x9c, 0xd5, 0xe5, 0x40, 0x1f, 0x43, 0xce, 0x75, + 0xac, 0xd1, 0x1f, 0x14, 0xba, 0x2e, 0x99, 0xf3, 0x7b, 0x3c, 0xe8, 0x91, 0x87, 0x65, 0x25, 0x27, + 0x01, 0x7d, 0xce, 0xce, 0x08, 0x38, 0xb3, 0x43, 0x2f, 0x3d, 0x86, 0x9c, 0x2b, 0x18, 0x55, 0x20, + 0xe3, 0xd4, 0x44, 0x05, 0xee, 0x71, 0x79, 0x2d, 0x74, 0x05, 0x52, 0x86, 0xfe, 0x05, 0xff, 0x38, + 0x2c, 0x21, 0xb3, 0x86, 0xd4, 0x86, 0xf2, 0x58, 0xa0, 0x40, 0x8f, 0x21, 0x63, 0x0c, 0xcf, 0x15, + 0xc7, 0xaa, 0xc7, 0xf6, 0xcf, 0xc1, 0x4f, 0x86, 0xe7, 0x3d, 0xad, 0xf5, 0x0c, 0x5f, 0x39, 0x7a, + 0x64, 0x0c, 0xcf, 0x9f, 0x31, 0xe3, 0x67, 0xa3, 0xc4, 0xfd, 0xa3, 0x5c, 0x42, 0xd6, 0xf1, 0x65, + 0xe8, 0x8f, 0xfd, 0x5b, 0xe5, 0x7c, 0xdc, 0x19, 0x19, 0xbc, 0xb8, 0x78, 0xdf, 0x4e, 0xdd, 0x81, + 0x25, 0x4b, 0xeb, 0x0c, 0x9c, 0xfa, 0x39, 0x3b, 0x68, 0x56, 0x10, 0x2b, 0xb3, 0x17, 0x07, 0x0e, + 0x24, 0x47, 0x52, 0x0f, 0x71, 0xdc, 0x99, 0xfe, 0x2e, 0x27, 0x10, 0x92, 0x22, 0x25, 0xc2, 0x52, + 0xa4, 0xbf, 0x8e, 0x43, 0xde, 0x57, 0x95, 0x47, 0x7f, 0xe8, 0xf3, 0xec, 0xa5, 0x90, 0xd8, 0xee, + 0xa3, 0xf5, 0xbe, 0x9e, 0x0c, 0x2e, 0x2c, 0xbe, 0xf8, 0xc2, 0xa2, 0x3e, 0x82, 0x70, 0x8a, 0xfb, + 0xc9, 0x85, 0x8b, 0xfb, 0x77, 0x01, 0xd1, 0xb2, 0xb4, 0x72, 0xa9, 0xdb, 0xda, 0xa0, 0xa3, 0x30, + 0xd5, 0x60, 0x7e, 0x58, 0xa4, 0x6f, 0xce, 0xe8, 0x8b, 0x63, 0xaa, 0x25, 0x7f, 0x19, 0x87, 0xac, + 0x63, 0x61, 0xff, 0x4f, 0xb7, 0xe0, 0xaf, 0x04, 0xc8, 0xba, 0x50, 0xc3, 0xa2, 0x9f, 0x97, 0xae, + 0x42, 0x9a, 0xdf, 0xa6, 0xd9, 0xf7, 0xa5, 0xbc, 0x15, 0xfa, 0x21, 0x47, 0x15, 0xb2, 0x7d, 0x6c, + 0xab, 0x34, 0xae, 0xb2, 0xd4, 0xcc, 0x6d, 0xdf, 0x79, 0x04, 0x79, 0xdf, 0xa7, 0xb9, 0x24, 0xd4, + 0x1e, 0xd6, 0x3f, 0x13, 0x63, 0xd5, 0xcc, 0x4f, 0x7f, 0xb6, 0x91, 0x38, 0xc4, 0x5f, 0x10, 0x27, + 0x23, 0xd7, 0x6b, 0x8d, 0x7a, 0xed, 0x99, 0x28, 0x54, 0xf3, 0x3f, 0xfd, 0xd9, 0x46, 0x46, 0xc6, + 0xb4, 0x30, 0x79, 0xe7, 0x19, 0x94, 0xc7, 0x0e, 0x26, 0x98, 0x7b, 0x23, 0x28, 0x3d, 0x39, 0x3d, + 0x3e, 0xd8, 0xaf, 0xed, 0x34, 0xeb, 0xca, 0xd9, 0x51, 0xb3, 0x2e, 0x0a, 0xe8, 0x3a, 0x2c, 0x1f, + 0xec, 0x7f, 0xd2, 0x68, 0x2a, 0xb5, 0x83, 0xfd, 0xfa, 0x61, 0x53, 0xd9, 0x69, 0x36, 0x77, 0x6a, + 0xcf, 0xc4, 0xf8, 0xf6, 0x6f, 0xf3, 0x50, 0xde, 0xd9, 0xad, 0xed, 0xef, 0x18, 0x46, 0x4f, 0x6b, + 0xa9, 0x34, 0x86, 0xd4, 0x20, 0x49, 0x6b, 0x09, 0x53, 0xff, 0x59, 0xaa, 0x4e, 0xaf, 0x36, 0xa3, + 0x3d, 0x48, 0xd1, 0x32, 0x03, 0x9a, 0xfe, 0x13, 0x53, 0x75, 0x46, 0xf9, 0x99, 0x4c, 0x86, 0x7a, + 0x94, 0xa9, 0x7f, 0x35, 0x55, 0xa7, 0x57, 0xa3, 0xd1, 0x01, 0x64, 0x1c, 0x5c, 0x77, 0xd6, 0xaf, + 0x46, 0xd5, 0x99, 0x25, 0x62, 0xb2, 0x34, 0x86, 0xbf, 0x4f, 0xff, 0xe1, 0xa9, 0x3a, 0xa3, 0x4e, + 0x8d, 0xf6, 0x21, 0xcd, 0x11, 0xb8, 0x19, 0xff, 0x30, 0x55, 0x67, 0x55, 0x9e, 0x91, 0x0c, 0x39, + 0xaf, 0xb2, 0x31, 0xfb, 0x37, 0xae, 0xea, 0x1c, 0x25, 0x78, 0xf4, 0x02, 0x8a, 0x41, 0xa4, 0x6f, + 0xbe, 0xff, 0xa4, 0xaa, 0x73, 0xd6, 0xb8, 0x89, 0xfc, 0x20, 0xec, 0x37, 0xdf, 0x7f, 0x53, 0xd5, + 0x39, 0x4b, 0xde, 0xe8, 0x47, 0xb0, 0x34, 0x09, 0xcb, 0xcd, 0xff, 0x1b, 0x55, 0x75, 0x81, 0x22, + 0x38, 0xea, 0x03, 0x0a, 0x81, 0xf3, 0x16, 0xf8, 0xab, 0xaa, 0xba, 0x48, 0x4d, 0x1c, 0xb5, 0xa1, + 0x3c, 0x0e, 0x91, 0xcd, 0xfb, 0x97, 0x55, 0x75, 0xee, 0xfa, 0x38, 0x1b, 0x25, 0x88, 0x17, 0xcd, + 0xfb, 0xd7, 0x55, 0x75, 0xee, 0x72, 0x39, 0x3a, 0x05, 0xf0, 0xe1, 0x1d, 0x73, 0xfc, 0x85, 0x55, + 0x9d, 0xa7, 0x70, 0x8e, 0x0c, 0x58, 0x0e, 0x03, 0x42, 0x16, 0xf9, 0x29, 0xab, 0xba, 0x50, 0x3d, + 0x9d, 0xe8, 0x73, 0x10, 0xd2, 0x98, 0xef, 0x27, 0xad, 0xea, 0x9c, 0x85, 0x75, 0xb2, 0x51, 0xde, + 0x35, 0x1e, 0xcd, 0xf1, 0xa3, 0x53, 0x75, 0x9e, 0xaa, 0xf4, 0x6e, 0xfd, 0x17, 0x5f, 0xaf, 0x09, + 0xbf, 0xfa, 0x7a, 0x4d, 0xf8, 0xaf, 0xaf, 0xd7, 0x84, 0xaf, 0xbe, 0x59, 0x8b, 0xfd, 0xea, 0x9b, + 0xb5, 0xd8, 0x7f, 0x7c, 0xb3, 0x16, 0xfb, 0xb3, 0x0f, 0x3b, 0x9a, 0xdd, 0x1d, 0x9e, 0x6f, 0xb6, + 0xf4, 0xfe, 0x96, 0xff, 0x6f, 0xd9, 0xb0, 0x5f, 0x78, 0xcf, 0xd3, 0x34, 0x4e, 0xdf, 0xfb, 0xbf, + 0x00, 0x00, 0x00, 0xff, 0xff, 0xb0, 0x2f, 0x03, 0x74, 0xe2, 0x3b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -8304,18 +8221,6 @@ func (m *ResponseDeliverTx) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.EvmTxInfo != nil { - { - size, err := m.EvmTxInfo.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } if len(m.Codespace) > 0 { i -= len(m.Codespace) copy(dAtA[i:], m.Codespace) @@ -8592,20 +8497,20 @@ func (m *ResponseApplySnapshotChunk) MarshalToSizedBuffer(dAtA []byte) (int, err } } if len(m.RefetchChunks) > 0 { - dAtA58 := make([]byte, len(m.RefetchChunks)*10) - var j57 int + dAtA57 := make([]byte, len(m.RefetchChunks)*10) + var j56 int for _, num := range m.RefetchChunks { for num >= 1<<7 { - dAtA58[j57] = uint8(uint64(num)&0x7f | 0x80) + dAtA57[j56] = uint8(uint64(num)&0x7f | 0x80) num >>= 7 - j57++ + j56++ } - dAtA58[j57] = uint8(num) - j57++ + dAtA57[j56] = uint8(num) + j56++ } - i -= j57 - copy(dAtA[i:], dAtA58[:j57]) - i = encodeVarintTypes(dAtA, i, uint64(j57)) + i -= j56 + copy(dAtA[i:], dAtA57[:j56]) + i = encodeVarintTypes(dAtA, i, uint64(j56)) i-- dAtA[i] = 0x12 } @@ -9178,18 +9083,6 @@ func (m *ExecTxResult) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.EvmTxInfo != nil { - { - size, err := m.EvmTxInfo.MarshalToSizedBuffer(dAtA[:i]) - if err != nil { - return 0, err - } - i -= size - i = encodeVarintTypes(dAtA, i, uint64(size)) - } - i-- - dAtA[i] = 0x4a - } if len(m.Codespace) > 0 { i -= len(m.Codespace) copy(dAtA[i:], m.Codespace) @@ -9630,12 +9523,12 @@ func (m *Misbehavior) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n71, err71 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err71 != nil { - return 0, err71 + n69, err69 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err69 != nil { + return 0, err69 } - i -= n71 - i = encodeVarintTypes(dAtA, i, uint64(n71)) + i -= n69 + i = encodeVarintTypes(dAtA, i, uint64(n69)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -9686,12 +9579,12 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { i-- dAtA[i] = 0x28 } - n73, err73 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) - if err73 != nil { - return 0, err73 + n71, err71 := github_com_gogo_protobuf_types.StdTimeMarshalTo(m.Time, dAtA[i-github_com_gogo_protobuf_types.SizeOfStdTime(m.Time):]) + if err71 != nil { + return 0, err71 } - i -= n73 - i = encodeVarintTypes(dAtA, i, uint64(n73)) + i -= n71 + i = encodeVarintTypes(dAtA, i, uint64(n71)) i-- dAtA[i] = 0x22 if m.Height != 0 { @@ -9717,48 +9610,6 @@ func (m *Evidence) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } -func (m *EvmTxInfo) Marshal() (dAtA []byte, err error) { - size := m.Size() - dAtA = make([]byte, size) - n, err := m.MarshalToSizedBuffer(dAtA[:size]) - if err != nil { - return nil, err - } - return dAtA[:n], nil -} - -func (m *EvmTxInfo) MarshalTo(dAtA []byte) (int, error) { - size := m.Size() - return m.MarshalToSizedBuffer(dAtA[:size]) -} - -func (m *EvmTxInfo) MarshalToSizedBuffer(dAtA []byte) (int, error) { - i := len(dAtA) - _ = i - var l int - _ = l - if len(m.TxHash) > 0 { - i -= len(m.TxHash) - copy(dAtA[i:], m.TxHash) - i = encodeVarintTypes(dAtA, i, uint64(len(m.TxHash))) - i-- - dAtA[i] = 0x1a - } - if m.Nonce != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.Nonce)) - i-- - dAtA[i] = 0x10 - } - if len(m.SenderAddress) > 0 { - i -= len(m.SenderAddress) - copy(dAtA[i:], m.SenderAddress) - i = encodeVarintTypes(dAtA, i, uint64(len(m.SenderAddress))) - i-- - dAtA[i] = 0xa - } - return len(dAtA) - i, nil -} - func (m *Snapshot) Marshal() (dAtA []byte, err error) { size := m.Size() dAtA = make([]byte, size) @@ -11080,10 +10931,6 @@ func (m *ResponseDeliverTx) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.EvmTxInfo != nil { - l = m.EvmTxInfo.Size() - n += 1 + l + sovTypes(uint64(l)) - } return n } @@ -11455,10 +11302,6 @@ func (m *ExecTxResult) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.EvmTxInfo != nil { - l = m.EvmTxInfo.Size() - n += 1 + l + sovTypes(uint64(l)) - } return n } @@ -11645,26 +11488,6 @@ func (m *Evidence) Size() (n int) { return n } -func (m *EvmTxInfo) Size() (n int) { - if m == nil { - return 0 - } - var l int - _ = l - l = len(m.SenderAddress) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - if m.Nonce != 0 { - n += 1 + sovTypes(uint64(m.Nonce)) - } - l = len(m.TxHash) - if l > 0 { - n += 1 + l + sovTypes(uint64(l)) - } - return n -} - func (m *Snapshot) Size() (n int) { if m == nil { return 0 @@ -18488,42 +18311,6 @@ func (m *ResponseDeliverTx) Unmarshal(dAtA []byte) error { } m.Codespace = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EvmTxInfo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.EvmTxInfo == nil { - m.EvmTxInfo = &EvmTxInfo{} - } - if err := m.EvmTxInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -20849,42 +20636,6 @@ func (m *ExecTxResult) Unmarshal(dAtA []byte) error { } m.Codespace = string(dAtA[iNdEx:postIndex]) iNdEx = postIndex - case 9: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field EvmTxInfo", wireType) - } - var msglen int - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - msglen |= int(b&0x7F) << shift - if b < 0x80 { - break - } - } - if msglen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + msglen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - if m.EvmTxInfo == nil { - m.EvmTxInfo = &EvmTxInfo{} - } - if err := m.EvmTxInfo.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { - return err - } - iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTypes(dAtA[iNdEx:]) @@ -22237,139 +21988,6 @@ func (m *Evidence) Unmarshal(dAtA []byte) error { } return nil } -func (m *EvmTxInfo) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: EvmTxInfo: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: EvmTxInfo: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field SenderAddress", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.SenderAddress = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - case 2: - if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field Nonce", wireType) - } - m.Nonce = 0 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - m.Nonce |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - case 3: - if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field TxHash", wireType) - } - var stringLen uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowTypes - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - stringLen |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - intStringLen := int(stringLen) - if intStringLen < 0 { - return ErrInvalidLengthTypes - } - postIndex := iNdEx + intStringLen - if postIndex < 0 { - return ErrInvalidLengthTypes - } - if postIndex > l { - return io.ErrUnexpectedEOF - } - m.TxHash = string(dAtA[iNdEx:postIndex]) - iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipTypes(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthTypes - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} func (m *Snapshot) Unmarshal(dAtA []byte) error { l := len(dAtA) iNdEx := 0 diff --git a/config/config.go b/config/config.go index 27085797e..ba401a784 100644 --- a/config/config.go +++ b/config/config.go @@ -800,16 +800,6 @@ type MempoolConfig struct { // blacklist the peer. CheckTxErrorBlacklistEnabled bool `mapstructure:"check-tx-error-blacklist-enabled"` CheckTxErrorThreshold int `mapstructure:"check-tx-error-threshold"` - - // Maximum number of transactions in the pending set - PendingSize int `mapstructure:"pending-size"` - - // Limit the total size of all txs in the pending set. - MaxPendingTxsBytes int64 `mapstructure:"max-pending-txs-bytes"` - - PendingTTLDuration time.Duration `mapstructure:"pending-ttl-duration"` - - PendingTTLNumBlocks int64 `mapstructure:"pending-ttl-num-blocks"` } // DefaultMempoolConfig returns a default configuration for the Tendermint mempool. @@ -827,10 +817,6 @@ func DefaultMempoolConfig() *MempoolConfig { TxNotifyThreshold: 0, CheckTxErrorBlacklistEnabled: false, CheckTxErrorThreshold: 0, - PendingSize: 5000, - MaxPendingTxsBytes: 1024 * 1024 * 1024, // 1GB - PendingTTLDuration: 0 * time.Second, - PendingTTLNumBlocks: 0, } } diff --git a/config/toml.go b/config/toml.go index ae0667010..4e6c7577d 100644 --- a/config/toml.go +++ b/config/toml.go @@ -405,14 +405,6 @@ check-tx-error-blacklist-enabled = {{ .Mempool.CheckTxErrorBlacklistEnabled }} check-tx-error-threshold = {{ .Mempool.CheckTxErrorThreshold }} -pending-size = {{ .Mempool.PendingSize }} - -max-pending-txs-bytes = {{ .Mempool.MaxPendingTxsBytes }} - -pending-ttl-duration = "{{ .Mempool.PendingTTLDuration }}" - -pending-ttl-num-blocks = {{ .Mempool.PendingTTLNumBlocks }} - ####################################################### ### State Sync Configuration Options ### ####################################################### diff --git a/internal/consensus/mempool_test.go b/internal/consensus/mempool_test.go index 6ef3849ad..e634d4b22 100644 --- a/internal/consensus/mempool_test.go +++ b/internal/consensus/mempool_test.go @@ -139,7 +139,7 @@ func checkTxsRange(ctx context.Context, t *testing.T, cs *State, start, end int) var rCode uint32 err := assertMempool(t, cs.txNotifier).CheckTx(ctx, txBytes, func(r *abci.ResponseCheckTx) { rCode = r.Code }, mempool.TxInfo{}) require.NoError(t, err, "error after checkTx") - require.Equal(t, code.CodeTypeOK, rCode, "checkTx code is error, txBytes %X, index=%d", txBytes, i) + require.Equal(t, code.CodeTypeOK, rCode, "checkTx code is error, txBytes %X", txBytes) } } @@ -166,7 +166,7 @@ func TestMempoolTxConcurrentWithCommit(t *testing.T) { require.NoError(t, err) newBlockHeaderCh := subscribe(ctx, t, cs.eventBus, types.EventQueryNewBlockHeader) - const numTxs int64 = 50 + const numTxs int64 = 100 go checkTxsRange(ctx, t, cs, 0, int(numTxs)) startTestRound(ctx, cs, cs.roundState.Height(), cs.roundState.Round()) @@ -308,18 +308,18 @@ func (app *CounterApplication) FinalizeBlock(_ context.Context, req *abci.Reques return res, nil } -func (app *CounterApplication) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTxV2, error) { +func (app *CounterApplication) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { app.mu.Lock() defer app.mu.Unlock() txValue := txAsUint64(req.Tx) if txValue != uint64(app.mempoolTxCount) { - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ + return &abci.ResponseCheckTx{ Code: code.CodeTypeBadNonce, - }}, nil + }, nil } app.mempoolTxCount++ - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{Code: code.CodeTypeOK}}, nil + return &abci.ResponseCheckTx{Code: code.CodeTypeOK}, nil } func txAsUint64(tx []byte) uint64 { @@ -331,6 +331,7 @@ func txAsUint64(tx []byte) uint64 { func (app *CounterApplication) Commit(context.Context) (*abci.ResponseCommit, error) { app.mu.Lock() defer app.mu.Unlock() + app.mempoolTxCount = app.txCount return &abci.ResponseCommit{}, nil } diff --git a/internal/consensus/reactor.go b/internal/consensus/reactor.go index 3ceadae90..3631fd1d8 100644 --- a/internal/consensus/reactor.go +++ b/internal/consensus/reactor.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "github.com/tendermint/tendermint/config" cstypes "github.com/tendermint/tendermint/internal/consensus/types" "github.com/tendermint/tendermint/internal/eventbus" "github.com/tendermint/tendermint/internal/p2p" @@ -122,7 +121,6 @@ type ConsSyncReactor interface { type Reactor struct { service.BaseService logger log.Logger - cfg *config.Config state *State eventBus *eventbus.EventBus @@ -150,7 +148,6 @@ func NewReactor( eventBus *eventbus.EventBus, waitSync bool, metrics *Metrics, - cfg *config.Config, ) *Reactor { r := &Reactor{ logger: logger, @@ -163,7 +160,6 @@ func NewReactor( peerEvents: peerEvents, readySignal: make(chan struct{}), channels: &channelBundle{}, - cfg: cfg, } r.BaseService = *service.NewBaseService(logger, "Consensus", r) @@ -650,12 +646,7 @@ func (r *Reactor) pickSendVote(ctx context.Context, ps *PeerState, votes types.V return false, nil } - if r.cfg.BaseConfig.LogLevel == log.LogLevelDebug { - psJson, err := ps.ToJSON() // expensive, so we only want to call if debug is on - if err != nil { - r.logger.Debug("sending vote message", "ps", string(psJson), "vote", vote) - } - } + r.logger.Debug("sending vote message", "ps", ps, "vote", vote) if err := voteCh.Send(ctx, p2p.Envelope{ To: ps.peerID, Message: &tmcons.Vote{ diff --git a/internal/consensus/reactor_test.go b/internal/consensus/reactor_test.go index 97927b235..8d840a14f 100644 --- a/internal/consensus/reactor_test.go +++ b/internal/consensus/reactor_test.go @@ -97,7 +97,6 @@ func setup( state.eventBus, true, NopMetrics(), - config.DefaultConfig(), ) reactor.SetStateChannel(rts.stateChannels[nodeID]) @@ -698,7 +697,6 @@ func TestSwitchToConsensusVoteExtensions(t *testing.T) { cs.eventBus, true, NopMetrics(), - config.DefaultConfig(), ) if testCase.shouldPanic { diff --git a/internal/mempool/mempool.go b/internal/mempool/mempool.go index 90ef114c5..b47f69d29 100644 --- a/internal/mempool/mempool.go +++ b/internal/mempool/mempool.go @@ -15,6 +15,7 @@ import ( "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/libs/clist" "github.com/tendermint/tendermint/libs/log" + tmmath "github.com/tendermint/tendermint/libs/math" "github.com/tendermint/tendermint/types" ) @@ -43,9 +44,6 @@ type TxMempool struct { // sizeBytes defines the total size of the mempool (sum of all tx bytes) sizeBytes int64 - // pendingSizeBytes defines the total size of the pending set (sum of all tx bytes) - pendingSizeBytes int64 - // cache defines a fixed-size cache of already seen transactions as this // reduces pressure on the proxyApp. cache TxCache @@ -84,10 +82,6 @@ type TxMempool struct { // index. i.e. older transactions are first. timestampIndex *WrappedTxList - // pendingTxs stores transactions that are not valid yet but might become valid - // if its checker returns Accepted - pendingTxs *PendingTxs - // A read/write lock is used to safe guard updates, insertions and deletions // from the mempool. A read-lock is implicitly acquired when executing CheckTx, // however, a caller must explicitly grab a write-lock via Lock when updating @@ -127,7 +121,6 @@ func NewTxMempool( timestampIndex: NewWrappedTxList(func(wtx1, wtx2 *WrappedTx) bool { return wtx1.timestamp.After(wtx2.timestamp) || wtx1.timestamp.Equal(wtx2.timestamp) }), - pendingTxs: NewPendingTxs(cfg), failedCheckTxCounts: map[types.NodeID]uint64{}, peerManager: peerManager, } @@ -180,28 +173,15 @@ func (txmp *TxMempool) Unlock() { // Size returns the number of valid transactions in the mempool. It is // thread-safe. func (txmp *TxMempool) Size() int { - return txmp.SizeWithoutPending() + txmp.PendingSize() -} - -func (txmp *TxMempool) SizeWithoutPending() int { return txmp.txStore.Size() } -// PendingSize returns the number of pending transactions in the mempool. -func (txmp *TxMempool) PendingSize() int { - return txmp.pendingTxs.Size() -} - // SizeBytes return the total sum in bytes of all the valid transactions in the // mempool. It is thread-safe. func (txmp *TxMempool) SizeBytes() int64 { return atomic.LoadInt64(&txmp.sizeBytes) } -func (txmp *TxMempool) PendingSizeBytes() int64 { - return atomic.LoadInt64(&txmp.pendingSizeBytes) -} - // FlushAppConn executes FlushSync on the mempool's proxyAppConn. // // NOTE: The caller must obtain a write-lock prior to execution. @@ -295,77 +275,41 @@ func (txmp *TxMempool) CheckTx( } res, err := txmp.proxyAppConn.CheckTx(ctx, &abci.RequestCheckTx{Tx: tx}) - - // when a transaction is removed/expired/rejected, this should be called - // The expire tx handler unreserves the pending nonce - removeHandler := func(removeFromCache bool) { - if removeFromCache { - txmp.cache.Remove(tx) - } - if res.ExpireTxHandler != nil { - res.ExpireTxHandler() - } - } - if err != nil { - removeHandler(true) + txmp.cache.Remove(tx) res.Log = txmp.AppendCheckTxErr(res.Log, err.Error()) } wtx := &WrappedTx{ - tx: tx, - hash: txHash, - timestamp: time.Now().UTC(), - height: txmp.height, - evmNonce: res.EVMNonce, - evmAddress: res.EVMSenderAddress, - isEVM: res.IsEVM, - removeHandler: removeHandler, + tx: tx, + hash: txHash, + timestamp: time.Now().UTC(), + height: txmp.height, } + // only add new transaction if checkTx passes if err == nil { - // only add new transaction if checkTx passes and is not pending - if !res.IsPendingTransaction { - err = txmp.addNewTransaction(wtx, res.ResponseCheckTx, txInfo) - if err != nil { - return err - } - } else { - // otherwise add to pending txs store - if res.Checker == nil { - return errors.New("no checker available for pending transaction") - } - if err := txmp.canAddPendingTx(wtx); err != nil { - // TODO: eviction strategy for pending transactions - removeHandler(true) - return err - } - atomic.AddInt64(&txmp.pendingSizeBytes, int64(wtx.Size())) - if err := txmp.pendingTxs.Insert(wtx, res, txInfo); err != nil { - return err - } + err = txmp.addNewTransaction(wtx, res, txInfo) + + if err != nil { + return err } } if cb != nil { - cb(res.ResponseCheckTx) + cb(res) } return nil } -func (txmp *TxMempool) isInMempool(tx types.Tx) bool { - existingTx := txmp.txStore.GetTxByHash(tx.Key()) - return existingTx != nil && !existingTx.removed -} - func (txmp *TxMempool) RemoveTxByKey(txKey types.TxKey) error { txmp.Lock() defer txmp.Unlock() // remove the committed transaction from the transaction store and indexes if wtx := txmp.txStore.GetTxByHash(txKey); wtx != nil { - txmp.removeTx(wtx, false, true, true) + txmp.removeTx(wtx, false) return nil } @@ -404,7 +348,7 @@ func (txmp *TxMempool) Flush() { txmp.timestampIndex.Reset() for _, wtx := range txmp.txStore.GetAllTxs() { - txmp.removeTx(wtx, false, false, true) + txmp.removeTx(wtx, false) } atomic.SwapInt64(&txmp.sizeBytes, 0) @@ -426,28 +370,42 @@ func (txmp *TxMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs { totalSize int64 ) - var txs []types.Tx - if uint64(txmp.SizeWithoutPending()) < txmp.config.TxNotifyThreshold { + // wTxs contains a list of *WrappedTx retrieved from the priority queue that + // need to be re-enqueued prior to returning. + wTxs := make([]*WrappedTx, 0, txmp.priorityIndex.NumTxs()) + defer func() { + for _, wtx := range wTxs { + txmp.priorityIndex.PushTx(wtx) + } + }() + + txs := make([]types.Tx, 0, txmp.priorityIndex.NumTxs()) + if uint64(txmp.Size()) < txmp.config.TxNotifyThreshold { // do not reap anything if threshold is not met return txs } - txmp.priorityIndex.ForEachTx(func(wtx *WrappedTx) bool { + for txmp.priorityIndex.NumTxs() > 0 { + wtx := txmp.priorityIndex.PopTx() + txs = append(txs, wtx.tx) + wTxs = append(wTxs, wtx) size := types.ComputeProtoSizeForTxs([]types.Tx{wtx.tx}) + // Ensure we have capacity for the transaction with respect to the + // transaction size. if maxBytes > -1 && totalSize+size > maxBytes { - return false + return txs[:len(txs)-1] } + totalSize += size + + // ensure we have capacity for the transaction with respect to total gas gas := totalGas + wtx.gasWanted if maxGas > -1 && gas > maxGas { - return false + return txs[:len(txs)-1] } totalGas = gas - - txs = append(txs, wtx.tx) - return true - }) + } return txs } @@ -462,17 +420,24 @@ func (txmp *TxMempool) ReapMaxTxs(max int) types.Txs { txmp.mtx.Lock() defer txmp.mtx.Unlock() - wTxs := txmp.priorityIndex.PeekTxs(max) - txs := make([]types.Tx, 0, len(wTxs)) - for _, wtx := range wTxs { + numTxs := txmp.priorityIndex.NumTxs() + if max < 0 { + max = numTxs + } + + cap := tmmath.MinInt(numTxs, max) + + // wTxs contains a list of *WrappedTx retrieved from the priority queue that + // need to be re-enqueued prior to returning. + wTxs := make([]*WrappedTx, 0, cap) + txs := make([]types.Tx, 0, cap) + for txmp.priorityIndex.NumTxs() > 0 && len(txs) < max { + wtx := txmp.priorityIndex.PopTx() txs = append(txs, wtx.tx) + wTxs = append(wTxs, wtx) } - if len(txs) < max { - // retrieve more from pending txs - pending := txmp.pendingTxs.Peek(max - len(txs)) - for _, ptx := range pending { - txs = append(txs, ptx.tx.tx) - } + for _, wtx := range wTxs { + txmp.priorityIndex.PushTx(wtx) } return txs } @@ -516,22 +481,11 @@ func (txmp *TxMempool) Update( // remove the committed transaction from the transaction store and indexes if wtx := txmp.txStore.GetTxByHash(tx.Key()); wtx != nil { - txmp.removeTx(wtx, false, false, true) - } - if execTxResult[i].EvmTxInfo != nil { - // remove any tx that has the same nonce (because the committed tx - // may be from block proposal and is never in the local mempool) - if wtx, _ := txmp.priorityIndex.GetTxWithSameNonce(&WrappedTx{ - evmAddress: execTxResult[i].EvmTxInfo.SenderAddress, - evmNonce: execTxResult[i].EvmTxInfo.Nonce, - }); wtx != nil { - txmp.removeTx(wtx, false, false, true) - } + txmp.removeTx(wtx, false) } } txmp.purgeExpiredTxs(blockHeight) - txmp.handlePendingTransactions() // If there any uncommitted transactions left in the mempool, we either // initiate re-CheckTx per remaining transaction or notify that remaining @@ -549,8 +503,7 @@ func (txmp *TxMempool) Update( } } - txmp.metrics.Size.Set(float64(txmp.SizeWithoutPending())) - txmp.metrics.PendingSize.Set(float64(txmp.PendingSize())) + txmp.metrics.Size.Set(float64(txmp.Size())) return nil } @@ -593,7 +546,9 @@ func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, res *abci.ResponseCheck txmp.metrics.FailedTxs.Add(1) - wtx.removeHandler(!txmp.config.KeepInvalidTxsInCache) + if !txmp.config.KeepInvalidTxsInCache { + txmp.cache.Remove(wtx.tx) + } if res.Code != abci.CodeTypeOK { txmp.mtxFailedCheckTxCounts.Lock() defer txmp.mtxFailedCheckTxCounts.Unlock() @@ -631,7 +586,7 @@ func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, res *abci.ResponseCheck if len(evictTxs) == 0 { // No room for the new incoming transaction so we just remove it from // the cache. - wtx.removeHandler(true) + txmp.cache.Remove(wtx.tx) txmp.logger.Error( "rejected incoming good transaction; mempool full", "tx", fmt.Sprintf("%X", wtx.tx.Hash()), @@ -647,7 +602,7 @@ func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, res *abci.ResponseCheck // - The transaction, toEvict, can be removed while a concurrent // reCheckTx callback is being executed for the same transaction. for _, toEvict := range evictTxs { - txmp.removeTx(toEvict, true, true, true) + txmp.removeTx(toEvict, true) txmp.logger.Debug( "evicted existing good transaction; mempool full", "old_tx", fmt.Sprintf("%X", toEvict.tx.Hash()), @@ -666,21 +621,18 @@ func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, res *abci.ResponseCheck txInfo.SenderID: {}, } - if txmp.isInMempool(wtx.tx) { - return nil - } - - if txmp.insertTx(wtx) { - txmp.logger.Debug( - "inserted good transaction", - "priority", wtx.priority, - "tx", fmt.Sprintf("%X", wtx.tx.Hash()), - "height", txmp.height, - "num_txs", txmp.SizeWithoutPending(), - ) - txmp.notifyTxsAvailable() - } + txmp.metrics.TxSizeBytes.Observe(float64(wtx.Size())) + txmp.metrics.Size.Set(float64(txmp.Size())) + txmp.insertTx(wtx) + txmp.logger.Debug( + "inserted good transaction", + "priority", wtx.priority, + "tx", fmt.Sprintf("%X", wtx.tx.Hash()), + "height", txmp.height, + "num_txs", txmp.Size(), + ) + txmp.notifyTxsAvailable() return nil } @@ -696,7 +648,7 @@ func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, res *abci.ResponseCheck // // This method is NOT executed for the initial CheckTx on a new transaction; // that case is handled by addNewTransaction instead. -func (txmp *TxMempool) handleRecheckResult(tx types.Tx, res *abci.ResponseCheckTxV2) { +func (txmp *TxMempool) handleRecheckResult(tx types.Tx, res *abci.ResponseCheckTx) { if txmp.recheckCursor == nil { return } @@ -739,11 +691,10 @@ func (txmp *TxMempool) handleRecheckResult(tx types.Tx, res *abci.ResponseCheckT if !txmp.txStore.IsTxRemoved(wtx.hash) { var err error if txmp.postCheck != nil { - err = txmp.postCheck(tx, res.ResponseCheckTx) + err = txmp.postCheck(tx, res) } - // we will treat a transaction that turns pending in a recheck as invalid and evict it - if res.Code == abci.CodeTypeOK && err == nil && !res.IsPendingTransaction { + if res.Code == abci.CodeTypeOK && err == nil { wtx.priority = res.Priority } else { txmp.logger.Debug( @@ -758,7 +709,7 @@ func (txmp *TxMempool) handleRecheckResult(tx types.Tx, res *abci.ResponseCheckT panic("corrupted reCheckTx cursor") } - txmp.removeTx(wtx, !txmp.config.KeepInvalidTxsInCache, true, true) + txmp.removeTx(wtx, !txmp.config.KeepInvalidTxsInCache) } } @@ -772,13 +723,12 @@ func (txmp *TxMempool) handleRecheckResult(tx types.Tx, res *abci.ResponseCheckT if txmp.recheckCursor == nil { txmp.logger.Debug("finished rechecking transactions") - if txmp.SizeWithoutPending() > 0 { + if txmp.Size() > 0 { txmp.notifyTxsAvailable() } } - txmp.metrics.Size.Set(float64(txmp.SizeWithoutPending())) - txmp.metrics.PendingSize.Set(float64(txmp.PendingSize())) + txmp.metrics.Size.Set(float64(txmp.Size())) } // updateReCheckTxs updates the recheck cursors using the gossipIndex. For @@ -830,7 +780,7 @@ func (txmp *TxMempool) updateReCheckTxs(ctx context.Context) { // the transaction can be inserted into the mempool. func (txmp *TxMempool) canAddTx(wtx *WrappedTx) error { var ( - numTxs = txmp.SizeWithoutPending() + numTxs = txmp.Size() sizeBytes = txmp.SizeBytes() ) @@ -846,38 +796,9 @@ func (txmp *TxMempool) canAddTx(wtx *WrappedTx) error { return nil } -func (txmp *TxMempool) canAddPendingTx(wtx *WrappedTx) error { - var ( - numTxs = txmp.PendingSize() - sizeBytes = txmp.PendingSizeBytes() - ) - - if numTxs >= txmp.config.PendingSize || int64(wtx.Size())+sizeBytes > txmp.config.MaxPendingTxsBytes { - return types.ErrMempoolPendingIsFull{ - NumTxs: numTxs, - MaxTxs: txmp.config.PendingSize, - TxsBytes: sizeBytes, - MaxTxsBytes: txmp.config.MaxPendingTxsBytes, - } - } - - return nil -} - -func (txmp *TxMempool) insertTx(wtx *WrappedTx) bool { - replacedTx, inserted := txmp.priorityIndex.PushTx(wtx) - if !inserted { - return false - } - txmp.metrics.TxSizeBytes.Observe(float64(wtx.Size())) - txmp.metrics.Size.Set(float64(txmp.SizeWithoutPending())) - txmp.metrics.PendingSize.Set(float64(txmp.PendingSize())) - - if replacedTx != nil { - txmp.removeTx(replacedTx, true, false, false) - } - +func (txmp *TxMempool) insertTx(wtx *WrappedTx) { txmp.txStore.SetTx(wtx) + txmp.priorityIndex.PushTx(wtx) txmp.heightIndex.Insert(wtx) txmp.timestampIndex.Insert(wtx) @@ -887,21 +808,16 @@ func (txmp *TxMempool) insertTx(wtx *WrappedTx) bool { gossipEl := txmp.gossipIndex.PushBack(wtx) wtx.gossipEl = gossipEl - txmp.metrics.InsertedTxs.Add(1) atomic.AddInt64(&txmp.sizeBytes, int64(wtx.Size())) - return true } -func (txmp *TxMempool) removeTx(wtx *WrappedTx, removeFromCache bool, shouldReenqueue bool, updatePriorityIndex bool) { +func (txmp *TxMempool) removeTx(wtx *WrappedTx, removeFromCache bool) { if txmp.txStore.IsTxRemoved(wtx.hash) { return } txmp.txStore.RemoveTx(wtx) - toBeReenqueued := []*WrappedTx{} - if updatePriorityIndex { - toBeReenqueued = txmp.priorityIndex.RemoveTx(wtx, shouldReenqueue) - } + txmp.priorityIndex.RemoveTx(wtx) txmp.heightIndex.Remove(wtx) txmp.timestampIndex.Remove(wtx) @@ -910,55 +826,16 @@ func (txmp *TxMempool) removeTx(wtx *WrappedTx, removeFromCache bool, shouldReen txmp.gossipIndex.Remove(wtx.gossipEl) wtx.gossipEl.DetachPrev() - txmp.metrics.RemovedTxs.Add(1) atomic.AddInt64(&txmp.sizeBytes, int64(-wtx.Size())) - wtx.removeHandler(removeFromCache) - - if shouldReenqueue { - for _, reenqueue := range toBeReenqueued { - txmp.removeTx(reenqueue, removeFromCache, false, true) - } - for _, reenqueue := range toBeReenqueued { - rtx := reenqueue.tx - go func() { - if err := txmp.CheckTx(context.Background(), rtx, nil, TxInfo{}); err != nil { - txmp.logger.Error(fmt.Sprintf("failed to reenqueue transaction %X due to %s", rtx.Hash(), err)) - } - }() - } + if removeFromCache { + txmp.cache.Remove(wtx.tx) } } -func (txmp *TxMempool) expire(blockHeight int64, wtx *WrappedTx) { - txmp.metrics.ExpiredTxs.Add(1) - txmp.logExpiredTx(blockHeight, wtx) - wtx.removeHandler(!txmp.config.KeepInvalidTxsInCache) -} - -func (txmp *TxMempool) logExpiredTx(blockHeight int64, wtx *WrappedTx) { - // defensive check - if wtx == nil { - return - } - - txmp.logger.Info( - "transaction expired", - "priority", wtx.priority, - "tx", fmt.Sprintf("%X", wtx.tx.Hash()), - "address", wtx.evmAddress, - "evm", wtx.isEVM, - "nonce", wtx.evmNonce, - "height", blockHeight, - "tx_height", wtx.height, - "tx_timestamp", wtx.timestamp, - "age", time.Since(wtx.timestamp), - ) -} - // purgeExpiredTxs removes all transactions that have exceeded their respective // height- and/or time-based TTLs from their respective indexes. Every expired -// transaction will be removed from the mempool, but preserved in the cache (except for pending txs). +// transaction will be removed from the mempool, but preserved in the cache. // // NOTE: purgeExpiredTxs must only be called during TxMempool#Update in which // the caller has a write-lock on the mempool and so we can safely iterate over @@ -1002,18 +879,12 @@ func (txmp *TxMempool) purgeExpiredTxs(blockHeight int64) { } for _, wtx := range expiredTxs { - txmp.expire(blockHeight, wtx) + txmp.removeTx(wtx, false) } - - // remove pending txs that have expired - txmp.pendingTxs.PurgeExpired(blockHeight, now, func(wtx *WrappedTx) { - atomic.AddInt64(&txmp.pendingSizeBytes, int64(-wtx.Size())) - txmp.expire(blockHeight, wtx) - }) } func (txmp *TxMempool) notifyTxsAvailable() { - if txmp.SizeWithoutPending() == 0 { + if txmp.Size() == 0 { return } @@ -1047,19 +918,3 @@ func (txmp *TxMempool) AppendCheckTxErr(existingLogs string, log string) string return builder.String() } - -func (txmp *TxMempool) handlePendingTransactions() { - accepted, rejected := txmp.pendingTxs.EvaluatePendingTransactions() - for _, tx := range accepted { - atomic.AddInt64(&txmp.pendingSizeBytes, int64(-tx.tx.Size())) - if err := txmp.addNewTransaction(tx.tx, tx.checkTxResponse.ResponseCheckTx, tx.txInfo); err != nil { - txmp.logger.Error(fmt.Sprintf("error adding pending transaction: %s", err)) - } - } - for _, tx := range rejected { - atomic.AddInt64(&txmp.pendingSizeBytes, int64(-tx.tx.Size())) - if !txmp.config.KeepInvalidTxsInCache { - tx.tx.removeHandler(true) - } - } -} diff --git a/internal/mempool/mempool_test.go b/internal/mempool/mempool_test.go index 650664b19..76e89c056 100644 --- a/internal/mempool/mempool_test.go +++ b/internal/mempool/mempool_test.go @@ -29,8 +29,6 @@ import ( // transaction priority based on the value in the key/value pair. type application struct { *kvstore.Application - - occupiedNonces map[string][]uint64 } type testTx struct { @@ -38,111 +36,40 @@ type testTx struct { priority int64 } -func (app *application) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTxV2, error) { - +func (app *application) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { var ( priority int64 sender string ) - if strings.HasPrefix(string(req.Tx), "evm") { - // format is evm-sender-0=account=priority=nonce - // split into respective vars - parts := bytes.Split(req.Tx, []byte("=")) - sender = string(parts[0]) - account := string(parts[1]) - v, err := strconv.ParseInt(string(parts[2]), 10, 64) - if err != nil { - // could not parse - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ - Priority: priority, - Code: 100, - GasWanted: 1, - }}, nil - } - nonce, err := strconv.ParseUint(string(parts[3]), 10, 64) - if err != nil { - // could not parse - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ - Priority: priority, - Code: 101, - GasWanted: 1, - }}, nil - } - if app.occupiedNonces == nil { - app.occupiedNonces = make(map[string][]uint64) - } - if _, exists := app.occupiedNonces[account]; !exists { - app.occupiedNonces[account] = []uint64{} - } - active := true - for i := uint64(0); i < nonce; i++ { - found := false - for _, occ := range app.occupiedNonces[account] { - if occ == i { - found = true - break - } - } - if !found { - active = false - break - } - } - app.occupiedNonces[account] = append(app.occupiedNonces[account], nonce) - return &abci.ResponseCheckTxV2{ - ResponseCheckTx: &abci.ResponseCheckTx{ - Priority: v, - Code: code.CodeTypeOK, - GasWanted: 1, - }, - EVMNonce: nonce, - EVMSenderAddress: account, - IsEVM: true, - IsPendingTransaction: !active, - Checker: func() abci.PendingTxCheckerResponse { return abci.Pending }, - ExpireTxHandler: func() { - idx := -1 - for i, n := range app.occupiedNonces[account] { - if n == nonce { - idx = i - break - } - } - if idx >= 0 { - app.occupiedNonces[account] = append(app.occupiedNonces[account][:idx], app.occupiedNonces[account][idx+1:]...) - } - }, - }, nil - } - // infer the priority from the raw transaction value (sender=key=value) parts := bytes.Split(req.Tx, []byte("=")) if len(parts) == 3 { v, err := strconv.ParseInt(string(parts[2]), 10, 64) if err != nil { - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ + return &abci.ResponseCheckTx{ Priority: priority, Code: 100, GasWanted: 1, - }}, nil + }, nil } priority = v sender = string(parts[0]) } else { - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ + return &abci.ResponseCheckTx{ Priority: priority, Code: 101, GasWanted: 1, - }}, nil + }, nil } - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{ + + return &abci.ResponseCheckTx{ Priority: priority, Sender: sender, Code: code.CodeTypeOK, GasWanted: 1, - }}, nil + }, nil } func setup(t testing.TB, app abciclient.Client, cacheSize int, options ...TxMempoolOption) *TxMempool { @@ -287,7 +214,6 @@ func TestTxMempool_Size(t *testing.T) { txmp := setup(t, client, 0) txs := checkTxs(ctx, t, txmp, 100, 0) require.Equal(t, len(txs), txmp.Size()) - require.Equal(t, 0, txmp.PendingSize()) require.Equal(t, int64(5690), txmp.SizeBytes()) rawTxs := make([]types.Tx, len(txs)) @@ -516,162 +442,6 @@ func TestTxMempool_CheckTxExceedsMaxSize(t *testing.T) { require.NoError(t, txmp.CheckTx(ctx, tx, nil, TxInfo{SenderID: 0})) } -func TestTxMempool_Prioritization(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()}) - if err := client.Start(ctx); err != nil { - t.Fatal(err) - } - t.Cleanup(client.Wait) - - txmp := setup(t, client, 100) - peerID := uint16(1) - - address1 := "0xeD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - address2 := "0xfD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - - // Generate transactions with different priorities - // there are two formats to comply with the above mocked CheckTX - // EVM: evm-sender=account=priority=nonce - // Non-EVM: sender=peer=priority - txs := [][]byte{ - []byte(fmt.Sprintf("sender-0-1=peer=%d", 9)), - []byte(fmt.Sprintf("sender-1-1=peer=%d", 8)), - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address2, 6, 0)), - []byte(fmt.Sprintf("sender-2-1=peer=%d", 5)), - []byte(fmt.Sprintf("sender-3-1=peer=%d", 4)), - } - evmTxs := [][]byte{ - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 7, 0)), - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 9, 1)), - } - - // copy the slice of txs and shuffle the order randomly - txsCopy := make([][]byte, len(txs)) - copy(txsCopy, txs) - rng := rand.New(rand.NewSource(time.Now().UnixNano())) - rng.Shuffle(len(txsCopy), func(i, j int) { - txsCopy[i], txsCopy[j] = txsCopy[j], txsCopy[i] - }) - txs = [][]byte{ - []byte(fmt.Sprintf("sender-0-1=peer=%d", 9)), - []byte(fmt.Sprintf("sender-1-1=peer=%d", 8)), - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 7, 0)), - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 9, 1)), - []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address2, 6, 0)), - []byte(fmt.Sprintf("sender-2-1=peer=%d", 5)), - []byte(fmt.Sprintf("sender-3-1=peer=%d", 4)), - } - txsCopy = append(txsCopy, evmTxs...) - - for i := range txsCopy { - require.NoError(t, txmp.CheckTx(ctx, txsCopy[i], nil, TxInfo{SenderID: peerID})) - } - - // Reap the transactions - reapedTxs := txmp.ReapMaxTxs(len(txs)) - // Check if the reaped transactions are in the correct order of their priorities - for _, tx := range txs { - fmt.Printf("expected: %s\n", string(tx)) - } - fmt.Println("**************") - for _, reapedTx := range reapedTxs { - fmt.Printf("received: %s\n", string(reapedTx)) - } - for i, reapedTx := range reapedTxs { - require.Equal(t, txs[i], []byte(reapedTx)) - } -} - -func TestTxMempool_PendingStoreSize(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()}) - if err := client.Start(ctx); err != nil { - t.Fatal(err) - } - t.Cleanup(client.Wait) - - txmp := setup(t, client, 100) - txmp.config.PendingSize = 1 - peerID := uint16(1) - - address1 := "0xeD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 1, 1)), nil, TxInfo{SenderID: peerID})) - err := txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 1, 2)), nil, TxInfo{SenderID: peerID}) - require.Error(t, err) - require.Contains(t, err.Error(), "mempool pending set is full") -} - -func TestTxMempool_RemoveCacheWhenPendingTxIsFull(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()}) - if err := client.Start(ctx); err != nil { - t.Fatal(err) - } - t.Cleanup(client.Wait) - - txmp := setup(t, client, 10) - txmp.config.PendingSize = 1 - peerID := uint16(1) - address1 := "0xeD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 1, 1)), nil, TxInfo{SenderID: peerID})) - err := txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 1, 2)), nil, TxInfo{SenderID: peerID}) - require.Error(t, err) - txCache := txmp.cache.(*LRUTxCache) - // Make sure the second tx is removed from cache - require.Equal(t, 1, len(txCache.cacheMap)) -} - -func TestTxMempool_EVMEviction(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()}) - if err := client.Start(ctx); err != nil { - t.Fatal(err) - } - t.Cleanup(client.Wait) - - txmp := setup(t, client, 100) - txmp.config.Size = 1 - peerID := uint16(1) - - address1 := "0xeD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - address2 := "0xfD23B3A9DE15e92B9ef9540E587B3661E15A12fA" - - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 1, 0)), nil, TxInfo{SenderID: peerID})) - // this should evict the previous tx - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 2, 0)), nil, TxInfo{SenderID: peerID})) - require.Equal(t, 1, txmp.priorityIndex.NumTxs()) - require.Equal(t, int64(2), txmp.priorityIndex.txs[0].priority) - - txmp.config.Size = 2 - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address1, 3, 1)), nil, TxInfo{SenderID: peerID})) - require.Equal(t, 0, txmp.pendingTxs.Size()) - require.Equal(t, 2, txmp.priorityIndex.NumTxs()) - // this would evict the tx with priority 2 and cause the tx with priority 3 to go pending - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address2, 4, 0)), nil, TxInfo{SenderID: peerID})) - time.Sleep(1 * time.Second) // reenqueue is async - require.Equal(t, 1, txmp.priorityIndex.NumTxs()) - tx := txmp.priorityIndex.txs[0] - require.Equal(t, 1, txmp.pendingTxs.Size()) - - require.NoError(t, txmp.CheckTx(ctx, []byte(fmt.Sprintf("evm-sender=%s=%d=%d", address2, 5, 1)), nil, TxInfo{SenderID: peerID})) - require.Equal(t, 2, txmp.priorityIndex.NumTxs()) - txmp.removeTx(tx, true, false, true) - // should not reenqueue - require.Equal(t, 1, txmp.priorityIndex.NumTxs()) - time.Sleep(1 * time.Second) // pendingTxs should still be one even after sleeping for a sec - require.Equal(t, 1, txmp.pendingTxs.Size()) -} - func TestTxMempool_CheckTxSamePeer(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() diff --git a/internal/mempool/metrics.gen.go b/internal/mempool/metrics.gen.go index cfff9ad4c..100c5e71c 100644 --- a/internal/mempool/metrics.gen.go +++ b/internal/mempool/metrics.gen.go @@ -20,12 +20,6 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics { Name: "size", Help: "Number of uncommitted transactions in the mempool.", }, labels).With(labelsAndValues...), - PendingSize: prometheus.NewGaugeFrom(stdprometheus.GaugeOpts{ - Namespace: namespace, - Subsystem: MetricsSubsystem, - Name: "pending_size", - Help: "Number of pending transactions in mempool", - }, labels).With(labelsAndValues...), TxSizeBytes: prometheus.NewHistogramFrom(stdprometheus.HistogramOpts{ Namespace: namespace, Subsystem: MetricsSubsystem, @@ -52,44 +46,22 @@ func PrometheusMetrics(namespace string, labelsAndValues ...string) *Metrics { Name: "evicted_txs", Help: "Number of evicted transactions.", }, labels).With(labelsAndValues...), - ExpiredTxs: prometheus.NewCounterFrom(stdprometheus.CounterOpts{ - Namespace: namespace, - Subsystem: MetricsSubsystem, - Name: "expired_txs", - Help: "Number of expired transactions.", - }, labels).With(labelsAndValues...), RecheckTimes: prometheus.NewCounterFrom(stdprometheus.CounterOpts{ Namespace: namespace, Subsystem: MetricsSubsystem, Name: "recheck_times", Help: "Number of times transactions are rechecked in the mempool.", }, labels).With(labelsAndValues...), - RemovedTxs: prometheus.NewCounterFrom(stdprometheus.CounterOpts{ - Namespace: namespace, - Subsystem: MetricsSubsystem, - Name: "removed_txs", - Help: "Number of removed tx from mempool", - }, labels).With(labelsAndValues...), - InsertedTxs: prometheus.NewCounterFrom(stdprometheus.CounterOpts{ - Namespace: namespace, - Subsystem: MetricsSubsystem, - Name: "inserted_txs", - Help: "Number of txs inserted to mempool", - }, labels).With(labelsAndValues...), } } func NopMetrics() *Metrics { return &Metrics{ Size: discard.NewGauge(), - PendingSize: discard.NewGauge(), TxSizeBytes: discard.NewHistogram(), FailedTxs: discard.NewCounter(), RejectedTxs: discard.NewCounter(), EvictedTxs: discard.NewCounter(), - ExpiredTxs: discard.NewCounter(), RecheckTimes: discard.NewCounter(), - RemovedTxs: discard.NewCounter(), - InsertedTxs: discard.NewCounter(), } } diff --git a/internal/mempool/metrics.go b/internal/mempool/metrics.go index fb68f7918..532307635 100644 --- a/internal/mempool/metrics.go +++ b/internal/mempool/metrics.go @@ -18,9 +18,6 @@ type Metrics struct { // Number of uncommitted transactions in the mempool. Size metrics.Gauge - // Number of pending transactions in mempool - PendingSize metrics.Gauge - // Histogram of transaction sizes in bytes. TxSizeBytes metrics.Histogram `metrics_buckettype:"exp" metrics_bucketsizes:"1,3,7"` @@ -41,18 +38,6 @@ type Metrics struct { //metrics:Number of evicted transactions. EvictedTxs metrics.Counter - // ExpiredTxs defines the number of expired transactions. These are valid - // transactions that passed CheckTx and existed in the mempool but were not - // get picked up in time and eventually got expired and removed from mempool - //metrics:Number of expired transactions. - ExpiredTxs metrics.Counter - // Number of times transactions are rechecked in the mempool. RecheckTimes metrics.Counter - - // Number of removed tx from mempool - RemovedTxs metrics.Counter - - // Number of txs inserted to mempool - InsertedTxs metrics.Counter } diff --git a/internal/mempool/priority_queue.go b/internal/mempool/priority_queue.go index ee9bc4873..e31997397 100644 --- a/internal/mempool/priority_queue.go +++ b/internal/mempool/priority_queue.go @@ -4,8 +4,6 @@ import ( "container/heap" "sort" "sync" - - tmmath "github.com/tendermint/tendermint/libs/math" ) var _ heap.Interface = (*TxPriorityQueue)(nil) @@ -13,39 +11,12 @@ var _ heap.Interface = (*TxPriorityQueue)(nil) // TxPriorityQueue defines a thread-safe priority queue for valid transactions. type TxPriorityQueue struct { mtx sync.RWMutex - txs []*WrappedTx // priority heap - // invariant 1: no duplicate nonce in the same queue - // invariant 2: no nonce gap in the same queue - // invariant 3: head of the queue must be in heap - evmQueue map[string][]*WrappedTx // sorted by nonce -} - -func insertToEVMQueue(queue []*WrappedTx, tx *WrappedTx, i int) []*WrappedTx { - // Make room for new value and add it - queue = append(queue, nil) - copy(queue[i+1:], queue[i:]) - queue[i] = tx - return queue -} - -// binarySearch finds the index at which tx should be inserted in queue -func binarySearch(queue []*WrappedTx, tx *WrappedTx) int { - low, high := 0, len(queue) - for low < high { - mid := low + (high-low)/2 - if queue[mid].IsBefore(tx) { - low = mid + 1 - } else { - high = mid - } - } - return low + txs []*WrappedTx } func NewTxPriorityQueue() *TxPriorityQueue { pq := &TxPriorityQueue{ - txs: make([]*WrappedTx, 0), - evmQueue: make(map[string][]*WrappedTx), + txs: make([]*WrappedTx, 0), } heap.Init(pq) @@ -53,49 +24,6 @@ func NewTxPriorityQueue() *TxPriorityQueue { return pq } -func (pq *TxPriorityQueue) GetTxWithSameNonce(tx *WrappedTx) (*WrappedTx, int) { - pq.mtx.RLock() - defer pq.mtx.RUnlock() - return pq.getTxWithSameNonceUnsafe(tx) -} - -func (pq *TxPriorityQueue) getTxWithSameNonceUnsafe(tx *WrappedTx) (*WrappedTx, int) { - queue, ok := pq.evmQueue[tx.evmAddress] - if !ok { - return nil, -1 - } - idx := binarySearch(queue, tx) - if idx < len(queue) && queue[idx].evmNonce == tx.evmNonce { - return queue[idx], idx - } - return nil, -1 -} - -func (pq *TxPriorityQueue) tryReplacementUnsafe(tx *WrappedTx) (replaced *WrappedTx, shouldDrop bool) { - if !tx.isEVM { - return nil, false - } - queue, ok := pq.evmQueue[tx.evmAddress] - if ok && len(queue) > 0 { - existing, idx := pq.getTxWithSameNonceUnsafe(tx) - if existing != nil { - if tx.priority > existing.priority { - // should replace - // replace heap if applicable - if hi, ok := pq.findTxIndexUnsafe(existing); ok { - heap.Remove(pq, hi) - heap.Push(pq, tx) // need to be in the heap since it has the same nonce - } - pq.evmQueue[tx.evmAddress][idx] = tx // replace queue item in-place - return existing, false - } - // tx should be dropped since it's dominated by an existing tx - return nil, true - } - } - return nil, false -} - // GetEvictableTxs attempts to find and return a list of *WrappedTx than can be // evicted to make room for another *WrappedTx with higher priority. If no such // list of *WrappedTx exists, nil will be returned. The returned list of *WrappedTx @@ -106,11 +34,8 @@ func (pq *TxPriorityQueue) GetEvictableTxs(priority, txSize, totalSize, cap int6 pq.mtx.RLock() defer pq.mtx.RUnlock() - txs := []*WrappedTx{} - txs = append(txs, pq.txs...) - for _, queue := range pq.evmQueue { - txs = append(txs, queue[1:]...) - } + txs := make([]*WrappedTx, len(pq.txs)) + copy(txs, pq.txs) sort.Slice(txs, func(i, j int) bool { return txs[i].priority < txs[j].priority @@ -141,257 +66,31 @@ func (pq *TxPriorityQueue) GetEvictableTxs(priority, txSize, totalSize, cap int6 return nil } -// requires read lock -func (pq *TxPriorityQueue) numQueuedUnsafe() int { - var result int - for _, queue := range pq.evmQueue { - result += len(queue) - } - // first items in queue are also in heap, subtract one - return result - len(pq.evmQueue) -} - // NumTxs returns the number of transactions in the priority queue. It is // thread safe. func (pq *TxPriorityQueue) NumTxs() int { pq.mtx.RLock() defer pq.mtx.RUnlock() - return len(pq.txs) + pq.numQueuedUnsafe() -} - -func (pq *TxPriorityQueue) removeQueuedEvmTxUnsafe(tx *WrappedTx) (removedIdx int) { - if queue, ok := pq.evmQueue[tx.evmAddress]; ok { - for i, t := range queue { - if t.tx.Key() == tx.tx.Key() { - pq.evmQueue[tx.evmAddress] = append(queue[:i], queue[i+1:]...) - if len(pq.evmQueue[tx.evmAddress]) == 0 { - delete(pq.evmQueue, tx.evmAddress) - } - return i - } - } - } - return -1 -} - -func (pq *TxPriorityQueue) findTxIndexUnsafe(tx *WrappedTx) (int, bool) { - // safety check for race situation where heapIndex is out of range of txs - if tx.heapIndex >= 0 && tx.heapIndex < len(pq.txs) && pq.txs[tx.heapIndex].tx.Key() == tx.tx.Key() { - return tx.heapIndex, true - } - - // heap index isn't trustable here, so attempt to find it - for i, t := range pq.txs { - if t.tx.Key() == tx.tx.Key() { - return i, true - } - } - return 0, false + return len(pq.txs) } // RemoveTx removes a specific transaction from the priority queue. -func (pq *TxPriorityQueue) RemoveTx(tx *WrappedTx, shouldReenqueue bool) (toBeReenqueued []*WrappedTx) { +func (pq *TxPriorityQueue) RemoveTx(tx *WrappedTx) { pq.mtx.Lock() defer pq.mtx.Unlock() - var removedIdx int - - if idx, ok := pq.findTxIndexUnsafe(tx); ok { - heap.Remove(pq, idx) - if tx.isEVM { - removedIdx = pq.removeQueuedEvmTxUnsafe(tx) - if !shouldReenqueue && len(pq.evmQueue[tx.evmAddress]) > 0 { - heap.Push(pq, pq.evmQueue[tx.evmAddress][0]) - } - } - } else if tx.isEVM { - removedIdx = pq.removeQueuedEvmTxUnsafe(tx) - } - if tx.isEVM && shouldReenqueue && len(pq.evmQueue[tx.evmAddress]) > 0 && removedIdx >= 0 { - toBeReenqueued = pq.evmQueue[tx.evmAddress][removedIdx:] + if tx.heapIndex < len(pq.txs) { + heap.Remove(pq, tx.heapIndex) } - return } -func (pq *TxPriorityQueue) pushTxUnsafe(tx *WrappedTx) { - if !tx.isEVM { - heap.Push(pq, tx) - return - } - - // if there aren't other waiting txs, init and return - queue, exists := pq.evmQueue[tx.evmAddress] - if !exists { - pq.evmQueue[tx.evmAddress] = []*WrappedTx{tx} - heap.Push(pq, tx) - return - } - - // this item is on the heap at the moment - first := queue[0] - - // the queue's first item (and ONLY the first item) must be on the heap - // if this tx is before the first item, then we need to remove the first - // item from the heap - if tx.IsBefore(first) { - if idx, ok := pq.findTxIndexUnsafe(first); ok { - heap.Remove(pq, idx) - } - heap.Push(pq, tx) - } - pq.evmQueue[tx.evmAddress] = insertToEVMQueue(queue, tx, binarySearch(queue, tx)) -} - -// These are available if we need to test the invariant checks -// these can be used to troubleshoot invariant violations -//func (pq *TxPriorityQueue) checkInvariants(msg string) { -// uniqHashes := make(map[string]bool) -// for idx, tx := range pq.txs { -// if tx == nil { -// pq.print() -// panic(fmt.Sprintf("DEBUG PRINT: found nil item on heap: idx=%d\n", idx)) -// } -// if tx.tx == nil { -// pq.print() -// panic(fmt.Sprintf("DEBUG PRINT: found nil tx.tx on heap: idx=%d\n", idx)) -// } -// if _, ok := uniqHashes[fmt.Sprintf("%x", tx.tx.Key())]; ok { -// pq.print() -// panic(fmt.Sprintf("INVARIANT (%s): duplicate hash=%x in heap", msg, tx.tx.Key())) -// } -// uniqHashes[fmt.Sprintf("%x", tx.tx.Key())] = true -// -// //if _, ok := pq.keys[tx.tx.Key()]; !ok { -// // pq.print() -// // panic(fmt.Sprintf("INVARIANT (%s): tx in heap but not in keys hash=%x", msg, tx.tx.Key())) -// //} -// -// if tx.isEVM { -// if queue, ok := pq.evmQueue[tx.evmAddress]; ok { -// if queue[0].tx.Key() != tx.tx.Key() { -// pq.print() -// panic(fmt.Sprintf("INVARIANT (%s): tx in heap but not at front of evmQueue hash=%x", msg, tx.tx.Key())) -// } -// } else { -// pq.print() -// panic(fmt.Sprintf("INVARIANT (%s): tx in heap but not in evmQueue hash=%x", msg, tx.tx.Key())) -// } -// } -// } -// -// // each item in all queues should be unique nonce -// for _, queue := range pq.evmQueue { -// hashes := make(map[string]bool) -// for idx, tx := range queue { -// if idx == 0 { -// _, ok := pq.findTxIndexUnsafe(tx) -// if !ok { -// pq.print() -// panic(fmt.Sprintf("INVARIANT (%s): did not find tx[0] hash=%x nonce=%d in heap", msg, tx.tx.Key(), tx.evmNonce)) -// } -// } -// //if _, ok := pq.keys[tx.tx.Key()]; !ok { -// // pq.print() -// // panic(fmt.Sprintf("INVARIANT (%s): tx in heap but not in keys hash=%x", msg, tx.tx.Key())) -// //} -// if _, ok := hashes[fmt.Sprintf("%x", tx.tx.Key())]; ok { -// pq.print() -// panic(fmt.Sprintf("INVARIANT (%s): duplicate hash=%x in queue nonce=%d", msg, tx.tx.Key(), tx.evmNonce)) -// } -// hashes[fmt.Sprintf("%x", tx.tx.Key())] = true -// } -// } -//} - -// for debugging situations where invariant violations occur -//func (pq *TxPriorityQueue) print() { -// fmt.Println("PRINT PRIORITY QUEUE ****************** ") -// for _, tx := range pq.txs { -// if tx == nil { -// fmt.Printf("DEBUG PRINT: heap (nil): nonce=?, hash=?\n") -// continue -// } -// if tx.tx == nil { -// fmt.Printf("DEBUG PRINT: heap (%s): nonce=%d, tx.tx is nil \n", tx.evmAddress, tx.evmNonce) -// continue -// } -// fmt.Printf("DEBUG PRINT: heap (%s): nonce=%d, hash=%x, time=%d\n", tx.evmAddress, tx.evmNonce, tx.tx.Key(), tx.timestamp.UnixNano()) -// } -// -// for addr, queue := range pq.evmQueue { -// for idx, tx := range queue { -// if tx == nil { -// fmt.Printf("DEBUG PRINT: found nil item on evmQueue(%s): idx=%d\n", addr, idx) -// continue -// } -// if tx.tx == nil { -// fmt.Printf("DEBUG PRINT: found nil tx.tx on evmQueue(%s): idx=%d\n", addr, idx) -// continue -// } -// -// fmt.Printf("DEBUG PRINT: evmQueue(%s)[%d]: nonce=%d, hash=%x, time=%d\n", tx.evmAddress, idx, tx.evmNonce, tx.tx.Key(), tx.timestamp.UnixNano()) -// } -// } -//} - // PushTx adds a valid transaction to the priority queue. It is thread safe. -func (pq *TxPriorityQueue) PushTx(tx *WrappedTx) (*WrappedTx, bool) { +func (pq *TxPriorityQueue) PushTx(tx *WrappedTx) { pq.mtx.Lock() defer pq.mtx.Unlock() - replacedTx, shouldDrop := pq.tryReplacementUnsafe(tx) - - // tx was not inserted, and nothing was replaced - if shouldDrop { - return nil, false - } - - // tx replaced an existing transaction - if replacedTx != nil { - return replacedTx, true - } - - // tx was not inserted yet, so insert it - pq.pushTxUnsafe(tx) - return nil, true -} - -func (pq *TxPriorityQueue) popTxUnsafe() *WrappedTx { - if len(pq.txs) == 0 { - return nil - } - - // remove the first item from the heap - x := heap.Pop(pq) - if x == nil { - return nil - } - tx := x.(*WrappedTx) - - // this situation is primarily for a test case that inserts nils - if tx == nil { - return nil - } - - // non-evm transactions do not have txs waiting on a nonce - if !tx.isEVM { - return tx - } - - // evm transactions can have txs waiting on this nonce - // if there are any, we should replace the heap with the next nonce - // for the address - - // remove the first item from the evmQueue - pq.removeQueuedEvmTxUnsafe(tx) - - // if there is a next item, now it can be added to the heap - if len(pq.evmQueue[tx.evmAddress]) > 0 { - heap.Push(pq, pq.evmQueue[tx.evmAddress][0]) - } - - return tx + heap.Push(pq, tx) } // PopTx removes the top priority transaction from the queue. It is thread safe. @@ -399,62 +98,12 @@ func (pq *TxPriorityQueue) PopTx() *WrappedTx { pq.mtx.Lock() defer pq.mtx.Unlock() - return pq.popTxUnsafe() -} - -// dequeue up to `max` transactions and reenqueue while locked -func (pq *TxPriorityQueue) ForEachTx(handler func(wtx *WrappedTx) bool) { - pq.mtx.Lock() - defer pq.mtx.Unlock() - - numTxs := len(pq.txs) + pq.numQueuedUnsafe() - - txs := make([]*WrappedTx, 0, numTxs) - - defer func() { - for _, tx := range txs { - pq.pushTxUnsafe(tx) - } - }() - - for i := 0; i < numTxs; i++ { - popped := pq.popTxUnsafe() - if popped == nil { - break - } - txs = append(txs, popped) - if !handler(popped) { - return - } - } -} - -// dequeue up to `max` transactions and reenqueue while locked -// TODO: use ForEachTx instead -func (pq *TxPriorityQueue) PeekTxs(max int) []*WrappedTx { - pq.mtx.Lock() - defer pq.mtx.Unlock() - - numTxs := len(pq.txs) + pq.numQueuedUnsafe() - if max < 0 { - max = numTxs - } - - cap := tmmath.MinInt(numTxs, max) - res := make([]*WrappedTx, 0, cap) - for i := 0; i < cap; i++ { - popped := pq.popTxUnsafe() - if popped == nil { - break - } - - res = append(res, popped) + x := heap.Pop(pq) + if x != nil { + return x.(*WrappedTx) } - for _, tx := range res { - pq.pushTxUnsafe(tx) - } - return res + return nil } // Push implements the Heap interface. @@ -474,8 +123,8 @@ func (pq *TxPriorityQueue) Pop() interface{} { old := pq.txs n := len(old) item := old[n-1] - old[n-1] = nil // avoid memory leak - setHeapIndex(item, -1) // for safety + old[n-1] = nil // avoid memory leak + item.heapIndex = -1 // for safety pq.txs = old[0 : n-1] return item } @@ -504,14 +153,6 @@ func (pq *TxPriorityQueue) Less(i, j int) bool { // Swap implements the Heap interface. It swaps two transactions in the queue. func (pq *TxPriorityQueue) Swap(i, j int) { pq.txs[i], pq.txs[j] = pq.txs[j], pq.txs[i] - setHeapIndex(pq.txs[i], i) - setHeapIndex(pq.txs[j], j) -} - -func setHeapIndex(tx *WrappedTx, i int) { - // a removed tx can be nil - if tx == nil { - return - } - tx.heapIndex = i + pq.txs[i].heapIndex = i + pq.txs[j].heapIndex = j } diff --git a/internal/mempool/priority_queue_test.go b/internal/mempool/priority_queue_test.go index 0c28b4fa3..ddc84806d 100644 --- a/internal/mempool/priority_queue_test.go +++ b/internal/mempool/priority_queue_test.go @@ -1,7 +1,6 @@ package mempool import ( - "fmt" "math/rand" "sort" "sync" @@ -11,171 +10,6 @@ import ( "github.com/stretchr/testify/require" ) -// TxTestCase represents a single test case for the TxPriorityQueue -type TxTestCase struct { - name string - inputTxs []*WrappedTx // Input transactions - expectedOutput []int64 // Expected order of transaction IDs -} - -func TestTxPriorityQueue_ReapHalf(t *testing.T) { - pq := NewTxPriorityQueue() - - // Generate transactions with different priorities and nonces - txs := make([]*WrappedTx, 100) - for i := range txs { - txs[i] = &WrappedTx{ - tx: []byte(fmt.Sprintf("tx-%d", i)), - priority: int64(i), - } - - // Push the transaction - pq.PushTx(txs[i]) - } - - //reverse sort txs by priority - sort.Slice(txs, func(i, j int) bool { - return txs[i].priority > txs[j].priority - }) - - // Reap half of the transactions - reapedTxs := pq.PeekTxs(len(txs) / 2) - - // Check if the reaped transactions are in the correct order of their priorities and nonces - for i, reapedTx := range reapedTxs { - require.Equal(t, txs[i].priority, reapedTx.priority) - } -} - -func TestAvoidPanicIfTransactionIsNil(t *testing.T) { - pq := NewTxPriorityQueue() - pq.Push(&WrappedTx{sender: "1", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}) - pq.txs = append(pq.txs, nil) - - var count int - pq.ForEachTx(func(tx *WrappedTx) bool { - count++ - return true - }) - - require.Equal(t, 1, count) -} - -func TestTxPriorityQueue_PriorityAndNonceOrdering(t *testing.T) { - testCases := []TxTestCase{ - { - name: "PriorityWithEVMAndNonEVMDuplicateNonce", - inputTxs: []*WrappedTx{ - {sender: "1", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}, - {sender: "3", isEVM: true, evmAddress: "0xabc", evmNonce: 3, priority: 9}, - {sender: "2", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 7}, - }, - expectedOutput: []int64{1, 3}, - }, - { - name: "PriorityWithEVMAndNonEVMDuplicateNonce", - inputTxs: []*WrappedTx{ - {sender: "1", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}, - {sender: "2", isEVM: false, priority: 9}, - {sender: "4", isEVM: true, evmAddress: "0xabc", evmNonce: 0, priority: 9}, // Same EVM address as first, lower nonce - {sender: "5", isEVM: true, evmAddress: "0xdef", evmNonce: 1, priority: 7}, - {sender: "3", isEVM: true, evmAddress: "0xdef", evmNonce: 0, priority: 8}, - {sender: "6", isEVM: false, priority: 6}, - {sender: "7", isEVM: true, evmAddress: "0xghi", evmNonce: 2, priority: 5}, - }, - expectedOutput: []int64{2, 4, 1, 3, 5, 6, 7}, - }, - { - name: "PriorityWithEVMAndNonEVM", - inputTxs: []*WrappedTx{ - {sender: "1", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}, - {sender: "2", isEVM: false, priority: 9}, - {sender: "4", isEVM: true, evmAddress: "0xabc", evmNonce: 0, priority: 9}, // Same EVM address as first, lower nonce - {sender: "5", isEVM: true, evmAddress: "0xdef", evmNonce: 1, priority: 7}, - {sender: "3", isEVM: true, evmAddress: "0xdef", evmNonce: 0, priority: 8}, - {sender: "6", isEVM: false, priority: 6}, - {sender: "7", isEVM: true, evmAddress: "0xghi", evmNonce: 2, priority: 5}, - }, - expectedOutput: []int64{2, 4, 1, 3, 5, 6, 7}, - }, - { - name: "IdenticalPrioritiesAndNoncesDifferentAddresses", - inputTxs: []*WrappedTx{ - {sender: "1", isEVM: true, evmAddress: "0xabc", evmNonce: 2, priority: 5}, - {sender: "2", isEVM: true, evmAddress: "0xdef", evmNonce: 2, priority: 5}, - {sender: "3", isEVM: true, evmAddress: "0xghi", evmNonce: 2, priority: 5}, - }, - expectedOutput: []int64{1, 2, 3}, - }, - { - name: "InterleavedEVAndNonEVMTransactions", - inputTxs: []*WrappedTx{ - {sender: "7", isEVM: false, priority: 15}, - {sender: "8", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 20}, - {sender: "9", isEVM: false, priority: 10}, - {sender: "10", isEVM: true, evmAddress: "0xdef", evmNonce: 2, priority: 20}, - }, - expectedOutput: []int64{8, 10, 7, 9}, - }, - { - name: "SameAddressPriorityDifferentNonces", - inputTxs: []*WrappedTx{ - {sender: "11", isEVM: true, evmAddress: "0xabc", evmNonce: 3, priority: 10}, - {sender: "12", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}, - {sender: "13", isEVM: true, evmAddress: "0xabc", evmNonce: 2, priority: 10}, - }, - expectedOutput: []int64{12, 13, 11}, - }, - { - name: "OneItem", - inputTxs: []*WrappedTx{ - {sender: "14", isEVM: true, evmAddress: "0xabc", evmNonce: 1, priority: 10}, - }, - expectedOutput: []int64{14}, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - pq := NewTxPriorityQueue() - now := time.Now() - - // Add input transactions to the queue and set timestamp to order inserted - for i, tx := range tc.inputTxs { - tx.timestamp = now.Add(time.Duration(i) * time.Second) - tx.tx = []byte(fmt.Sprintf("%d", time.Now().UnixNano())) - pq.PushTx(tx) - } - - results := pq.PeekTxs(len(tc.inputTxs)) - // Validate the order of transactions - require.Len(t, results, len(tc.expectedOutput)) - for i, expectedTxID := range tc.expectedOutput { - tx := results[i] - require.Equal(t, fmt.Sprintf("%d", expectedTxID), tx.sender) - } - }) - } -} - -func TestTxPriorityQueue_SameAddressDifferentNonces(t *testing.T) { - pq := NewTxPriorityQueue() - address := "0x123" - - // Insert transactions with the same address but different nonces and priorities - pq.PushTx(&WrappedTx{isEVM: true, evmAddress: address, evmNonce: 2, priority: 10, tx: []byte("tx1")}) - pq.PushTx(&WrappedTx{isEVM: true, evmAddress: address, evmNonce: 1, priority: 5, tx: []byte("tx2")}) - pq.PushTx(&WrappedTx{isEVM: true, evmAddress: address, evmNonce: 3, priority: 15, tx: []byte("tx3")}) - - // Pop transactions and verify they are in the correct order of nonce - tx1 := pq.PopTx() - require.Equal(t, uint64(1), tx1.evmNonce) - tx2 := pq.PopTx() - require.Equal(t, uint64(2), tx2.evmNonce) - tx3 := pq.PopTx() - require.Equal(t, uint64(3), tx3.evmNonce) -} - func TestTxPriorityQueue(t *testing.T) { pq := NewTxPriorityQueue() numTxs := 1000 @@ -191,7 +25,6 @@ func TestTxPriorityQueue(t *testing.T) { pq.PushTx(&WrappedTx{ priority: int64(i), timestamp: time.Now(), - tx: []byte(fmt.Sprintf("%d", i)), }) wg.Done() @@ -209,7 +42,6 @@ func TestTxPriorityQueue(t *testing.T) { pq.PushTx(&WrappedTx{ priority: 1000, timestamp: now, - tx: []byte(fmt.Sprintf("%d", time.Now().UnixNano())), }) require.Equal(t, 1001, pq.NumTxs()) @@ -309,33 +141,6 @@ func TestTxPriorityQueue_GetEvictableTxs(t *testing.T) { } } -func TestTxPriorityQueue_RemoveTxEvm(t *testing.T) { - pq := NewTxPriorityQueue() - - tx1 := &WrappedTx{ - priority: 1, - isEVM: true, - evmAddress: "0xabc", - evmNonce: 1, - tx: []byte("tx1"), - } - tx2 := &WrappedTx{ - priority: 1, - isEVM: true, - evmAddress: "0xabc", - evmNonce: 2, - tx: []byte("tx2"), - } - - pq.PushTx(tx1) - pq.PushTx(tx2) - - pq.RemoveTx(tx1, false) - - result := pq.PopTx() - require.Equal(t, tx2, result) -} - func TestTxPriorityQueue_RemoveTx(t *testing.T) { pq := NewTxPriorityQueue() rng := rand.New(rand.NewSource(time.Now().UnixNano())) @@ -347,7 +152,6 @@ func TestTxPriorityQueue_RemoveTx(t *testing.T) { x := rng.Intn(100000) pq.PushTx(&WrappedTx{ priority: int64(x), - tx: []byte(fmt.Sprintf("%d", i)), }) values[i] = x @@ -359,95 +163,14 @@ func TestTxPriorityQueue_RemoveTx(t *testing.T) { max := values[len(values)-1] wtx := pq.txs[pq.NumTxs()/2] - pq.RemoveTx(wtx, false) + pq.RemoveTx(wtx) require.Equal(t, numTxs-1, pq.NumTxs()) require.Equal(t, int64(max), pq.PopTx().priority) require.Equal(t, numTxs-2, pq.NumTxs()) require.NotPanics(t, func() { - pq.RemoveTx(&WrappedTx{heapIndex: numTxs}, false) - pq.RemoveTx(&WrappedTx{heapIndex: numTxs + 1}, false) + pq.RemoveTx(&WrappedTx{heapIndex: numTxs}) + pq.RemoveTx(&WrappedTx{heapIndex: numTxs + 1}) }) require.Equal(t, numTxs-2, pq.NumTxs()) } - -func TestTxPriorityQueue_TryReplacement(t *testing.T) { - for _, test := range []struct { - tx *WrappedTx - existing []*WrappedTx - expectedReplaced bool - expectedDropped bool - expectedQueue []*WrappedTx - expectedHeap []*WrappedTx - }{ - // non-evm transaction is inserted into empty queue - {&WrappedTx{isEVM: false}, []*WrappedTx{}, false, false, []*WrappedTx{{isEVM: false}}, []*WrappedTx{{isEVM: false}}}, - // evm transaction is inserted into empty queue - {&WrappedTx{isEVM: true, evmAddress: "addr1"}, []*WrappedTx{}, false, false, []*WrappedTx{{isEVM: true, evmAddress: "addr1"}}, []*WrappedTx{{isEVM: true, evmAddress: "addr1"}}}, - // evm transaction (new nonce) is inserted into queue with existing tx (lower nonce) - { - &WrappedTx{isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 100, tx: []byte("abc")}, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, false, false, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - {isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 100, tx: []byte("abc")}, - }, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - {isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 100, tx: []byte("abc")}, - }, - }, - // evm transaction (new nonce) is not inserted because it's a duplicate nonce and same priority - { - &WrappedTx{isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("abc")}, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, false, true, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, - }, - // evm transaction (new nonce) replaces the existing nonce transaction because its priority is higher - { - &WrappedTx{isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 101, tx: []byte("abc")}, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, true, false, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 101, tx: []byte("abc")}, - }, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 101, tx: []byte("abc")}, - }, - }, - { - &WrappedTx{isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 100, tx: []byte("abc")}, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - {isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 99, tx: []byte("ghi")}, - }, true, false, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - {isEVM: true, evmAddress: "addr1", evmNonce: 1, priority: 100, tx: []byte("abc")}, - }, []*WrappedTx{ - {isEVM: true, evmAddress: "addr1", evmNonce: 0, priority: 100, tx: []byte("def")}, - }, - }, - } { - pq := NewTxPriorityQueue() - for _, e := range test.existing { - pq.PushTx(e) - } - replaced, inserted := pq.PushTx(test.tx) - if test.expectedReplaced { - require.NotNil(t, replaced) - } else { - require.Nil(t, replaced) - } - require.Equal(t, test.expectedDropped, !inserted) - for i, q := range pq.evmQueue[test.tx.evmAddress] { - require.Equal(t, test.expectedQueue[i].tx.Key(), q.tx.Key()) - require.Equal(t, test.expectedQueue[i].priority, q.priority) - require.Equal(t, test.expectedQueue[i].evmNonce, q.evmNonce) - } - for i, q := range pq.txs { - require.Equal(t, test.expectedHeap[i].tx.Key(), q.tx.Key()) - require.Equal(t, test.expectedHeap[i].priority, q.priority) - require.Equal(t, test.expectedHeap[i].evmNonce, q.evmNonce) - } - } -} diff --git a/internal/mempool/tx.go b/internal/mempool/tx.go index 9366ac7fa..c7113c951 100644 --- a/internal/mempool/tx.go +++ b/internal/mempool/tx.go @@ -1,13 +1,10 @@ package mempool import ( - "errors" "sort" "sync" "time" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/internal/libs/clist" "github.com/tendermint/tendermint/types" ) @@ -66,20 +63,6 @@ type WrappedTx struct { // transaction in the mempool can be evicted when it is simultaneously having // a reCheckTx callback executed. removed bool - - // this is the callback that can be called when a transaction is removed - removeHandler func(removeFromCache bool) - - // evm properties that aid in prioritization - evmAddress string - evmNonce uint64 - isEVM bool -} - -// IsBefore returns true if the WrappedTx is before the given WrappedTx -// this applies to EVM transactions only -func (wtx *WrappedTx) IsBefore(tx *WrappedTx) bool { - return wtx.evmNonce < tx.evmNonce } func (wtx *WrappedTx) Size() int { @@ -89,9 +72,9 @@ func (wtx *WrappedTx) Size() int { // TxStore implements a thread-safe mapping of valid transaction(s). // // NOTE: -// - Concurrent read-only access to a *WrappedTx object is OK. However, mutative -// access is not allowed. Regardless, it is not expected for the mempool to -// need mutative access. +// - Concurrent read-only access to a *WrappedTx object is OK. However, mutative +// access is not allowed. Regardless, it is not expected for the mempool to +// need mutative access. type TxStore struct { mtx sync.RWMutex hashTxs map[types.TxKey]*WrappedTx // primary index @@ -308,144 +291,3 @@ func (wtl *WrappedTxList) Remove(wtx *WrappedTx) { i++ } } - -type PendingTxs struct { - mtx *sync.RWMutex - txs []TxWithResponse - config *config.MempoolConfig - sizeBytes uint64 -} - -type TxWithResponse struct { - tx *WrappedTx - checkTxResponse *abci.ResponseCheckTxV2 - txInfo TxInfo -} - -func NewPendingTxs(conf *config.MempoolConfig) *PendingTxs { - return &PendingTxs{ - mtx: &sync.RWMutex{}, - txs: []TxWithResponse{}, - config: conf, - sizeBytes: 0, - } -} -func (p *PendingTxs) EvaluatePendingTransactions() ( - acceptedTxs []TxWithResponse, - rejectedTxs []TxWithResponse, -) { - poppedIndices := []int{} - p.mtx.Lock() - defer p.mtx.Unlock() - for i := 0; i < len(p.txs); i++ { - switch p.txs[i].checkTxResponse.Checker() { - case abci.Accepted: - acceptedTxs = append(acceptedTxs, p.txs[i]) - poppedIndices = append(poppedIndices, i) - case abci.Rejected: - rejectedTxs = append(rejectedTxs, p.txs[i]) - poppedIndices = append(poppedIndices, i) - } - } - p.popTxsAtIndices(poppedIndices) - return -} - -// assume mtx is already acquired -func (p *PendingTxs) popTxsAtIndices(indices []int) { - if len(indices) == 0 { - return - } - newTxs := []TxWithResponse{} - start := 0 - for _, idx := range indices { - if idx <= start-1 { - panic("indices popped from pending tx store should be sorted without duplicate") - } - if idx >= len(p.txs) { - panic("indices popped from pending tx store out of range") - } - p.sizeBytes -= uint64(p.txs[idx].tx.Size()) - newTxs = append(newTxs, p.txs[start:idx]...) - start = idx + 1 - } - newTxs = append(newTxs, p.txs[start:]...) - p.txs = newTxs -} - -func (p *PendingTxs) Insert(tx *WrappedTx, resCheckTx *abci.ResponseCheckTxV2, txInfo TxInfo) error { - p.mtx.Lock() - defer p.mtx.Unlock() - - if len(p.txs) >= p.config.PendingSize || uint64(tx.Size())+p.sizeBytes > uint64(p.config.MaxPendingTxsBytes) { - return errors.New("pending store is full") - } - - p.txs = append(p.txs, TxWithResponse{ - tx: tx, - checkTxResponse: resCheckTx, - txInfo: txInfo, - }) - p.sizeBytes += uint64(tx.Size()) - return nil -} - -func (p *PendingTxs) Peek(max int) []TxWithResponse { - p.mtx.RLock() - defer p.mtx.RUnlock() - // priority is fifo - if max > len(p.txs) { - return p.txs - } - return p.txs[:max] -} - -func (p *PendingTxs) Size() int { - p.mtx.RLock() - defer p.mtx.RUnlock() - return len(p.txs) -} - -func (p *PendingTxs) PurgeExpired(blockHeight int64, now time.Time, cb func(wtx *WrappedTx)) { - p.mtx.Lock() - defer p.mtx.Unlock() - - if len(p.txs) == 0 { - return - } - - // txs retains the ordering of insertion - if p.config.TTLNumBlocks > 0 { - idxFirstNotExpiredTx := len(p.txs) - for i, ptx := range p.txs { - // once found, we can break because these are ordered - if (blockHeight - ptx.tx.height) <= p.config.TTLNumBlocks { - idxFirstNotExpiredTx = i - break - } else { - cb(ptx.tx) - p.sizeBytes -= uint64(ptx.tx.Size()) - } - } - p.txs = p.txs[idxFirstNotExpiredTx:] - } - - if len(p.txs) == 0 { - return - } - - if p.config.TTLDuration > 0 { - idxFirstNotExpiredTx := len(p.txs) - for i, ptx := range p.txs { - // once found, we can break because these are ordered - if now.Sub(ptx.tx.timestamp) <= p.config.TTLDuration { - idxFirstNotExpiredTx = i - break - } else { - cb(ptx.tx) - p.sizeBytes -= uint64(ptx.tx.Size()) - } - } - p.txs = p.txs[idxFirstNotExpiredTx:] - } -} diff --git a/internal/mempool/tx_test.go b/internal/mempool/tx_test.go index 152730b33..c6d494b04 100644 --- a/internal/mempool/tx_test.go +++ b/internal/mempool/tx_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/require" - abci "github.com/tendermint/tendermint/abci/types" - "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/types" ) @@ -231,134 +229,3 @@ func TestWrappedTxList_Remove(t *testing.T) { sort.Ints(expected) require.Equal(t, expected, got) } - -func TestPendingTxsPopTxsGood(t *testing.T) { - pendingTxs := NewPendingTxs(config.TestMempoolConfig()) - for _, test := range []struct { - origLen int - popIndices []int - expected []int - }{ - { - origLen: 1, - popIndices: []int{}, - expected: []int{0}, - }, { - origLen: 1, - popIndices: []int{0}, - expected: []int{}, - }, { - origLen: 2, - popIndices: []int{0}, - expected: []int{1}, - }, { - origLen: 2, - popIndices: []int{1}, - expected: []int{0}, - }, { - origLen: 2, - popIndices: []int{0, 1}, - expected: []int{}, - }, { - origLen: 3, - popIndices: []int{1}, - expected: []int{0, 2}, - }, { - origLen: 3, - popIndices: []int{0, 2}, - expected: []int{1}, - }, { - origLen: 3, - popIndices: []int{0, 1, 2}, - expected: []int{}, - }, { - origLen: 5, - popIndices: []int{0, 1, 4}, - expected: []int{2, 3}, - }, { - origLen: 5, - popIndices: []int{1, 3}, - expected: []int{0, 2, 4}, - }, - } { - pendingTxs.txs = []TxWithResponse{} - for i := 0; i < test.origLen; i++ { - pendingTxs.txs = append(pendingTxs.txs, TxWithResponse{ - tx: &WrappedTx{tx: []byte{}}, - txInfo: TxInfo{SenderID: uint16(i)}}) - } - pendingTxs.popTxsAtIndices(test.popIndices) - require.Equal(t, len(test.expected), len(pendingTxs.txs)) - for i, e := range test.expected { - require.Equal(t, e, int(pendingTxs.txs[i].txInfo.SenderID)) - } - } -} - -func TestPendingTxsPopTxsBad(t *testing.T) { - pendingTxs := NewPendingTxs(config.TestMempoolConfig()) - // out of range - require.Panics(t, func() { pendingTxs.popTxsAtIndices([]int{0}) }) - // out of order - pendingTxs.txs = []TxWithResponse{{}, {}, {}} - require.Panics(t, func() { pendingTxs.popTxsAtIndices([]int{1, 0}) }) - // duplicate - require.Panics(t, func() { pendingTxs.popTxsAtIndices([]int{2, 2}) }) -} - -func TestPendingTxs_InsertCondition(t *testing.T) { - mempoolCfg := config.TestMempoolConfig() - - // First test exceeding number of txs - mempoolCfg.PendingSize = 2 - - pendingTxs := NewPendingTxs(mempoolCfg) - - // Transaction setup - tx1 := &WrappedTx{ - tx: types.Tx("tx1_data"), - priority: 1, - } - tx1Size := tx1.Size() - - tx2 := &WrappedTx{ - tx: types.Tx("tx2_data"), - priority: 2, - } - tx2Size := tx2.Size() - - err := pendingTxs.Insert(tx1, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.Nil(t, err) - - err = pendingTxs.Insert(tx2, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.Nil(t, err) - - // Should fail due to pending store size limit - tx3 := &WrappedTx{ - tx: types.Tx("tx3_data_exceeding_pending_size"), - priority: 3, - } - - err = pendingTxs.Insert(tx3, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.NotNil(t, err) - - // Second test exceeding byte size condition - mempoolCfg.PendingSize = 5 - pendingTxs = NewPendingTxs(mempoolCfg) - mempoolCfg.MaxPendingTxsBytes = int64(tx1Size + tx2Size) - - err = pendingTxs.Insert(tx1, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.Nil(t, err) - - err = pendingTxs.Insert(tx2, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.Nil(t, err) - - // Should fail due to exceeding max pending transaction bytes - tx3 = &WrappedTx{ - tx: types.Tx("tx3_small_but_exceeds_byte_limit"), - priority: 3, - } - - err = pendingTxs.Insert(tx3, &abci.ResponseCheckTxV2{}, TxInfo{}) - require.NotNil(t, err) -} diff --git a/internal/proxy/client.go b/internal/proxy/client.go index f3ab28f5c..fa1d8c66e 100644 --- a/internal/proxy/client.go +++ b/internal/proxy/client.go @@ -169,7 +169,7 @@ func (app *proxyClient) Flush(ctx context.Context) error { return app.client.Flush(ctx) } -func (app *proxyClient) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTxV2, error) { +func (app *proxyClient) CheckTx(ctx context.Context, req *types.RequestCheckTx) (*types.ResponseCheckTx, error) { defer addTimeSample(app.metrics.MethodTiming.With("method", "check_tx", "type", "sync"))() return app.client.CheckTx(ctx, req) } diff --git a/internal/rpc/core/mempool.go b/internal/rpc/core/mempool.go index c351c5ba2..7cd1bcd7d 100644 --- a/internal/rpc/core/mempool.go +++ b/internal/rpc/core/mempool.go @@ -158,9 +158,6 @@ func (env *Environment) UnconfirmedTxs(ctx context.Context, req *coretypes.Reque skipCount := validateSkipCount(page, perPage) txs := env.Mempool.ReapMaxTxs(skipCount + tmmath.MinInt(perPage, totalCount-skipCount)) - if skipCount > len(txs) { - skipCount = len(txs) - } result := txs[skipCount:] return &coretypes.ResultUnconfirmedTxs{ @@ -188,7 +185,7 @@ func (env *Environment) CheckTx(ctx context.Context, req *coretypes.RequestCheck if err != nil { return nil, err } - return &coretypes.ResultCheckTx{ResponseCheckTx: *res.ResponseCheckTx}, nil + return &coretypes.ResultCheckTx{ResponseCheckTx: *res}, nil } func (env *Environment) RemoveTx(ctx context.Context, req *coretypes.RequestRemoveTx) error { diff --git a/internal/state/helpers_test.go b/internal/state/helpers_test.go index 1d0d59441..4284bad68 100644 --- a/internal/state/helpers_test.go +++ b/internal/state/helpers_test.go @@ -302,8 +302,8 @@ func (app *testApp) FinalizeBlock(_ context.Context, req *abci.RequestFinalizeBl }, nil } -func (app *testApp) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTxV2, error) { - return &abci.ResponseCheckTxV2{ResponseCheckTx: &abci.ResponseCheckTx{}}, nil +func (app *testApp) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { + return &abci.ResponseCheckTx{}, nil } func (app *testApp) Commit(context.Context) (*abci.ResponseCommit, error) { diff --git a/node/node.go b/node/node.go index d3075434e..0cd8a62bf 100644 --- a/node/node.go +++ b/node/node.go @@ -349,7 +349,6 @@ func makeNode( eventBus, waitSync, nodeMetrics.consensus, - cfg, ) node.router.AddChDescToBeAdded(consensus.GetStateChannelDescriptor(), csReactor.SetStateChannel) diff --git a/proto/tendermint/abci/types.proto b/proto/tendermint/abci/types.proto index 89393e83f..c814e80b2 100644 --- a/proto/tendermint/abci/types.proto +++ b/proto/tendermint/abci/types.proto @@ -309,7 +309,6 @@ message ResponseDeliverTx { repeated Event events = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic string codespace = 8; - EvmTxInfo evm_tx_info = 9; } message ResponseEndBlock { @@ -460,7 +459,6 @@ message ExecTxResult { repeated Event events = 7 [(gogoproto.nullable) = false, (gogoproto.jsontag) = "events,omitempty"]; // nondeterministic string codespace = 8; - EvmTxInfo evm_tx_info = 9; } // TxResult contains results of executing the transaction. @@ -567,12 +565,6 @@ message Evidence { int64 total_voting_power = 5; } -message EvmTxInfo { - string senderAddress = 1; - uint64 nonce = 2; - string txHash = 3; -} - //---------------------------------------- // State Sync Types diff --git a/proto/tendermint/crypto/keys.pb.go b/proto/tendermint/crypto/keys.pb.go index 24c6c1b1b..62a109cbd 100644 --- a/proto/tendermint/crypto/keys.pb.go +++ b/proto/tendermint/crypto/keys.pb.go @@ -27,6 +27,7 @@ const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package // PublicKey defines the keys available for use with Tendermint Validators type PublicKey struct { // Types that are valid to be assigned to Sum: + // // *PublicKey_Ed25519 // *PublicKey_Secp256K1 // *PublicKey_Sr25519 diff --git a/proto/tendermint/mempool/types.pb.go b/proto/tendermint/mempool/types.pb.go index 11e259551..ffe5ab359 100644 --- a/proto/tendermint/mempool/types.pb.go +++ b/proto/tendermint/mempool/types.pb.go @@ -68,6 +68,7 @@ func (m *Txs) GetTxs() [][]byte { type Message struct { // Types that are valid to be assigned to Sum: + // // *Message_Txs Sum isMessage_Sum `protobuf_oneof:"sum"` } diff --git a/proto/tendermint/p2p/conn.pb.go b/proto/tendermint/p2p/conn.pb.go index 47a3bb0cd..16ee463a6 100644 --- a/proto/tendermint/p2p/conn.pb.go +++ b/proto/tendermint/p2p/conn.pb.go @@ -158,6 +158,7 @@ func (m *PacketMsg) GetData() []byte { type Packet struct { // Types that are valid to be assigned to Sum: + // // *Packet_PacketPing // *Packet_PacketPong // *Packet_PacketMsg diff --git a/proto/tendermint/types/types.pb.go b/proto/tendermint/types/types.pb.go index 3671bf7a1..1fdefc056 100644 --- a/proto/tendermint/types/types.pb.go +++ b/proto/tendermint/types/types.pb.go @@ -1294,6 +1294,7 @@ func (m *TxProof) GetProof() *crypto.Proof { type Evidence struct { // Types that are valid to be assigned to Sum: + // // *Evidence_DuplicateVoteEvidence // *Evidence_LightClientAttackEvidence Sum isEvidence_Sum `protobuf_oneof:"sum"` diff --git a/rpc/client/mock/abci.go b/rpc/client/mock/abci.go index 27d779554..142d64d19 100644 --- a/rpc/client/mock/abci.go +++ b/rpc/client/mock/abci.go @@ -60,7 +60,7 @@ func (a ABCIApp) BroadcastTxCommit(ctx context.Context, tx types.Tx) (*coretypes return nil, err } - res := &coretypes.ResultBroadcastTxCommit{CheckTx: *resp.ResponseCheckTx} + res := &coretypes.ResultBroadcastTxCommit{CheckTx: *resp} if res.CheckTx.IsErr() { return res, nil } diff --git a/test/e2e/app/app.go b/test/e2e/app/app.go index b127fa744..885b49f39 100644 --- a/test/e2e/app/app.go +++ b/test/e2e/app/app.go @@ -163,14 +163,14 @@ func (app *Application) InitChain(_ context.Context, req *abci.RequestInitChain) } // CheckTx implements ABCI. -func (app *Application) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTxV2, error) { +func (app *Application) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*abci.ResponseCheckTx, error) { app.mu.Lock() defer app.mu.Unlock() _, _, err := parseTx(req.Tx) if err != nil { - return &abci.ResponseCheckTxV2{ - ResponseCheckTx: &abci.ResponseCheckTx{Code: code.CodeTypeEncodingError}, + return &abci.ResponseCheckTx{ + Code: code.CodeTypeEncodingError, }, nil } @@ -178,9 +178,7 @@ func (app *Application) CheckTx(_ context.Context, req *abci.RequestCheckTx) (*a time.Sleep(time.Duration(app.cfg.CheckTxDelayMS) * time.Millisecond) } - return &abci.ResponseCheckTxV2{ - ResponseCheckTx: &abci.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}, - }, nil + return &abci.ResponseCheckTx{Code: code.CodeTypeOK, GasWanted: 1}, nil } // FinalizeBlock implements ABCI. diff --git a/types/mempool.go b/types/mempool.go index a3a0c831e..36e877508 100644 --- a/types/mempool.go +++ b/types/mempool.go @@ -4,7 +4,6 @@ import ( "crypto/sha256" "errors" "fmt" - tmproto "github.com/tendermint/tendermint/proto/tendermint/types" ) @@ -85,25 +84,6 @@ func (e ErrMempoolIsFull) Error() string { ) } -// ErrMempoolPendingIsFull defines an error where there are too many pending transactions -// not processed yet -type ErrMempoolPendingIsFull struct { - NumTxs int - MaxTxs int - TxsBytes int64 - MaxTxsBytes int64 -} - -func (e ErrMempoolPendingIsFull) Error() string { - return fmt.Sprintf( - "mempool pending set is full: number of txs %d (max: %d), total txs bytes %d (max: %d)", - e.NumTxs, - e.MaxTxs, - e.TxsBytes, - e.MaxTxsBytes, - ) -} - // ErrPreCheck defines an error where a transaction fails a pre-check. type ErrPreCheck struct { Reason error diff --git a/types/tx.go b/types/tx.go index 5b7c2377e..0a37d1e9d 100644 --- a/types/tx.go +++ b/types/tx.go @@ -184,7 +184,7 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error { for i, cur := range allCopy { // allCopy is sorted, so any duplicated data will be adjacent. if i+1 < len(allCopy) && bytes.Equal(cur, allCopy[i+1]) { - return fmt.Errorf("found duplicate transaction with hash: %x", cur.Key()) + return fmt.Errorf("found duplicate transaction with hash: %x", cur.Hash()) } }