diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-funder.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-funder.nomad.j2 index 3f6f8e9b7..a3fd93b84 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-funder.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-funder.nomad.j2 @@ -64,8 +64,8 @@ job "{{ job.name }}" { fi done - TOPOLOGY=$(curl -s https://{{ .Address }}:{{ .Port }}/topology) - ETHEREUM_ADDRESS=$(echo ${TOPOLOGY} | jq -r '.self["Ethereum Address"]') + TOPOLOGY=$(curl -s https://{{ .Address }}:{{ .Port }}/v1/debug/topology) + ETHEREUM_ADDRESS=$(echo ${TOPOLOGY} | jq -r '.topology.self["Ethereum Address"]') {{- range nomadService "mev-commit-geth-bootnode1" }} {{- if contains "http" .Tags }} diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 index a9759de1c..73e455fa3 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit-oracle.nomad.j2 @@ -147,10 +147,10 @@ job "{{ job.name }}" { {{- end }} {{- range nomadService "mev-commit-geth-bootnode1" }} {{- if contains "http" .Tags }} - MEV_ORACLE_SETTLEMENT_RPC_URL="http://{{ .Address }}:{{ .Port }}" + MEV_ORACLE_SETTLEMENT_RPC_URL_HTTP="http://{{ .Address }}:{{ .Port }}" {{- end }} {{- if contains "ws" .Tags }} - MEV_ORACLE_SETTLEMENT_WS_RPC_ENDPOINT="ws://{{ .Address}}:{{ .Port }}" + MEV_ORACLE_SETTLEMENT_RPC_URL_WS="ws://{{ .Address}}:{{ .Port }}" {{- end }} {{- end }} {{- range nomadService "{% endraw %}{{ job.name }}{% raw %}" }} @@ -186,8 +186,8 @@ job "{{ job.name }}" { {%- raw %} {{- range nomadService "mev-commit-provider-node1" }} {{ if contains "http" .Tags }} - TOPOLOGY=$(curl https://{{ .Address}}:{{ .Port }}/topology) - PROVIDER_ETHEREUM_ADDRESS=$(echo ${TOPOLOGY} | jq -r '.self["Ethereum Address"]') + TOPOLOGY=$(curl https://{{ .Address}}:{{ .Port }}/v1/debug/topology) + PROVIDER_ETHEREUM_ADDRESS=$(echo ${TOPOLOGY} | jq -r '.topology.self["Ethereum Address"]') export MEV_ORACLE_OVERRIDE_WINNERS=${PROVIDER_ETHEREUM_ADDRESS} {{ end }} {{- end }} diff --git a/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 b/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 index 30ce395a0..9fd2c9a13 100644 --- a/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 +++ b/infrastructure/nomad/playbooks/templates/jobs/mev-commit.nomad.j2 @@ -109,10 +109,10 @@ job "{{ job.name }}" { {{- if contains "http" .Tags }} # Fetch topology data - TOPOLOGY=$(curl https://{{ .Address }}:{{ .Port }}/topology) + TOPOLOGY=$(curl https://{{ .Address }}:{{ .Port }}/v1/debug/topology) # Extract peerId (assuming the response format is JSON and jq is available) - PEER_ID=$(echo $TOPOLOGY | jq -r '.self.Underlay') + PEER_ID=$(echo $TOPOLOGY | jq -r '.topology.self.Underlay') {{- else if contains "p2p" .Tags }} diff --git a/oracle/cmd/main.go b/oracle/cmd/main.go index 913ad924a..e0dd72f66 100644 --- a/oracle/cmd/main.go +++ b/oracle/cmd/main.go @@ -101,13 +101,20 @@ var ( EnvVars: []string{"MEV_ORACLE_L1_RPC_URL"}, }) - optionSettlementRPCUrl = altsrc.NewStringFlag(&cli.StringFlag{ - Name: "settlement-rpc-url", - Usage: "URL for settlement RPC", - EnvVars: []string{"MEV_ORACLE_SETTLEMENT_RPC_URL"}, + optionSettlementRPCUrlHTTP = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "settlement-rpc-url-http", + Usage: "URL for settlement RPC endpoint over HTTP", + EnvVars: []string{"MEV_ORACLE_SETTLEMENT_RPC_URL_HTTP"}, Value: "http://localhost:8545", }) + optionSettlementRPCUrlWS = altsrc.NewStringFlag(&cli.StringFlag{ + Name: "settlement-rpc-url-ws", + Usage: "URL for settlement RPC over WebSocket", + EnvVars: []string{"MEV_ORACLE_SETTLEMENT_RPC_URL_WS"}, + Value: "http://localhost:8546", + }) + optionOracleContractAddr = altsrc.NewStringFlag(&cli.StringFlag{ Name: "oracle-contract-addr", Usage: "address of the oracle contract", @@ -214,7 +221,8 @@ func main() { optionLogLevel, optionLogTags, optionL1RPCUrl, - optionSettlementRPCUrl, + optionSettlementRPCUrlHTTP, + optionSettlementRPCUrlWS, optionOracleContractAddr, optionPreconfContractAddr, optionBlockTrackerContractAddr, @@ -287,12 +295,21 @@ func launchOracleWithConfig(c *cli.Context) error { } logger.Info("key signer account", "address", keySigner.GetAddress().Hex(), "url", keySigner.String()) + rpcURL := c.String(optionSettlementRPCUrlHTTP.Name) + if c.IsSet(optionSettlementRPCUrlWS.Name) { + rpcURL = c.String(optionSettlementRPCUrlWS.Name) + } + + if rpcURL == "" { + return fmt.Errorf("settlement rpc url is empty") + } + nd, err := node.NewNode(&node.Options{ Logger: logger, KeySigner: keySigner, HTTPPort: c.Int(optionHTTPPort.Name), L1RPCUrl: c.String(optionL1RPCUrl.Name), - SettlementRPCUrl: c.String(optionSettlementRPCUrl.Name), + SettlementRPCUrl: rpcURL, OracleContractAddr: common.HexToAddress(c.String(optionOracleContractAddr.Name)), PreconfContractAddr: common.HexToAddress(c.String(optionPreconfContractAddr.Name)), BlockTrackerContractAddr: common.HexToAddress(c.String(optionBlockTrackerContractAddr.Name)), diff --git a/p2p/gen/go/debugapi/v1/debugapi.pb.go b/p2p/gen/go/debugapi/v1/debugapi.pb.go new file mode 100644 index 000000000..334838f30 --- /dev/null +++ b/p2p/gen/go/debugapi/v1/debugapi.pb.go @@ -0,0 +1,627 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.31.0 +// protoc (unknown) +// source: debugapi/v1/debugapi.proto + +package debugapiv1 + +import ( + _ "buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go/buf/validate" + _ "github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2/options" + _ "google.golang.org/genproto/googleapis/api/annotations" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + structpb "google.golang.org/protobuf/types/known/structpb" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type EmptyMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *EmptyMessage) Reset() { + *x = EmptyMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *EmptyMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*EmptyMessage) ProtoMessage() {} + +func (x *EmptyMessage) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use EmptyMessage.ProtoReflect.Descriptor instead. +func (*EmptyMessage) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{0} +} + +type TopologyResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Topology *structpb.Struct `protobuf:"bytes,1,opt,name=topology,proto3" json:"topology,omitempty"` +} + +func (x *TopologyResponse) Reset() { + *x = TopologyResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TopologyResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TopologyResponse) ProtoMessage() {} + +func (x *TopologyResponse) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TopologyResponse.ProtoReflect.Descriptor instead. +func (*TopologyResponse) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{1} +} + +func (x *TopologyResponse) GetTopology() *structpb.Struct { + if x != nil { + return x.Topology + } + return nil +} + +type PendingTransactionsResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + PendingTransactions []*TransactionInfo `protobuf:"bytes,1,rep,name=pending_transactions,json=pendingTransactions,proto3" json:"pending_transactions,omitempty"` +} + +func (x *PendingTransactionsResponse) Reset() { + *x = PendingTransactionsResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PendingTransactionsResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PendingTransactionsResponse) ProtoMessage() {} + +func (x *PendingTransactionsResponse) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PendingTransactionsResponse.ProtoReflect.Descriptor instead. +func (*PendingTransactionsResponse) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{2} +} + +func (x *PendingTransactionsResponse) GetPendingTransactions() []*TransactionInfo { + if x != nil { + return x.PendingTransactions + } + return nil +} + +type TransactionInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` + Nonce int64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` + Created string `protobuf:"bytes,3,opt,name=created,proto3" json:"created,omitempty"` +} + +func (x *TransactionInfo) Reset() { + *x = TransactionInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TransactionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TransactionInfo) ProtoMessage() {} + +func (x *TransactionInfo) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TransactionInfo.ProtoReflect.Descriptor instead. +func (*TransactionInfo) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{3} +} + +func (x *TransactionInfo) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +func (x *TransactionInfo) GetNonce() int64 { + if x != nil { + return x.Nonce + } + return 0 +} + +func (x *TransactionInfo) GetCreated() string { + if x != nil { + return x.Created + } + return "" +} + +type CancelTransactionReq struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (x *CancelTransactionReq) Reset() { + *x = CancelTransactionReq{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelTransactionReq) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelTransactionReq) ProtoMessage() {} + +func (x *CancelTransactionReq) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancelTransactionReq.ProtoReflect.Descriptor instead. +func (*CancelTransactionReq) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{4} +} + +func (x *CancelTransactionReq) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +type CancelTransactionResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` +} + +func (x *CancelTransactionResponse) Reset() { + *x = CancelTransactionResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelTransactionResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelTransactionResponse) ProtoMessage() {} + +func (x *CancelTransactionResponse) ProtoReflect() protoreflect.Message { + mi := &file_debugapi_v1_debugapi_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CancelTransactionResponse.ProtoReflect.Descriptor instead. +func (*CancelTransactionResponse) Descriptor() ([]byte, []int) { + return file_debugapi_v1_debugapi_proto_rawDescGZIP(), []int{5} +} + +func (x *CancelTransactionResponse) GetTxHash() string { + if x != nil { + return x.TxHash + } + return "" +} + +var File_debugapi_v1_debugapi_proto protoreflect.FileDescriptor + +var file_debugapi_v1_debugapi_proto_rawDesc = []byte{ + 0x0a, 0x1a, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, + 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x64, 0x65, + 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x6f, 0x70, 0x65, 0x6e, 0x61, 0x70, 0x69, 0x76, 0x32, 0x2f, + 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, 0x72, 0x75, 0x63, 0x74, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x62, 0x75, 0x66, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, + 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0x64, 0x0a, 0x0c, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x3a, 0x54, 0x92, 0x41, 0x51, 0x0a, 0x4f, 0x2a, 0x0d, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x32, 0x3e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x20, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x6e, 0x6f, 0x74, + 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x70, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x2e, 0x22, 0x96, 0x01, 0x0a, 0x10, 0x54, 0x6f, 0x70, + 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4f, 0x0a, + 0x08, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x42, 0x1a, 0x92, 0x41, 0x17, 0x32, 0x15, 0x54, + 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6e, + 0x6f, 0x64, 0x65, 0x2e, 0x52, 0x08, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x3a, 0x31, + 0x92, 0x41, 0x2e, 0x0a, 0x2c, 0x2a, 0x08, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x32, + 0x15, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0xd2, 0x01, 0x08, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, + 0x79, 0x22, 0x99, 0x02, 0x0a, 0x1b, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x95, 0x01, 0x0a, 0x14, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1c, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x54, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x42, 0x44, + 0x92, 0x41, 0x41, 0x32, 0x3f, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x70, 0x65, 0x6e, + 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x73, + 0x74, 0x72, 0x79, 0x2e, 0x52, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x62, 0x92, 0x41, 0x5f, 0x0a, 0x5d, + 0x2a, 0x19, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x32, 0x2a, 0x54, 0x72, 0x61, + 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65, + 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0xd2, 0x01, 0x13, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xa5, 0x04, + 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x91, 0x01, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, + 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, + 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, + 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, + 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x69, 0x6e, + 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, + 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x06, 0x74, + 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3a, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x42, 0x24, 0x92, 0x41, 0x21, 0x32, 0x1f, 0x4e, 0x6f, 0x6e, 0x63, 0x65, + 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x05, 0x6e, 0x6f, 0x6e, 0x63, + 0x65, 0x12, 0x45, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x42, 0x2b, 0x92, 0x41, 0x28, 0x32, 0x26, 0x54, 0x69, 0x6d, 0x65, 0x20, 0x77, 0x68, + 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x2e, 0x52, + 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x3a, 0xfa, 0x01, 0x92, 0x41, 0xf6, 0x01, 0x0a, + 0x59, 0x2a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, + 0x6e, 0x66, 0x6f, 0x32, 0x2a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, 0x64, 0x20, 0x62, + 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0xd2, + 0x01, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0xd2, 0x01, 0x05, 0x6e, 0x6f, 0x6e, 0x63, 0x65, + 0xd2, 0x01, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x32, 0x98, 0x01, 0x7b, 0x22, 0x74, + 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, + 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, + 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, + 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, + 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x2c, 0x20, 0x22, 0x6e, 0x6f, 0x6e, + 0x63, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x2c, 0x20, 0x22, 0x63, 0x72, 0x65, 0x61, + 0x74, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x32, 0x30, 0x30, 0x39, 0x2d, 0x31, 0x31, 0x2d, 0x31, + 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x20, 0x2b, 0x30, 0x30, 0x30, 0x30, + 0x20, 0x55, 0x54, 0x43, 0x20, 0x6d, 0x3d, 0x2b, 0x30, 0x2e, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x31, 0x22, 0x7d, 0x22, 0xae, 0x03, 0x0a, 0x14, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x12, 0xe1, + 0x01, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0xc7, 0x01, 0x92, 0x41, 0x67, 0x32, 0x53, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, + 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, + 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, + 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0xba, 0x48, 0x5a, + 0xba, 0x01, 0x57, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x12, 0x29, 0x74, 0x78, + 0x5f, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6d, 0x75, 0x73, 0x74, 0x20, 0x62, 0x65, 0x20, 0x61, 0x20, + 0x36, 0x34, 0x2d, 0x63, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x20, 0x68, 0x65, 0x78, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x1a, 0x21, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x6d, 0x61, + 0x74, 0x63, 0x68, 0x65, 0x73, 0x28, 0x27, 0x5e, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, + 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x24, 0x27, 0x29, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, + 0x73, 0x68, 0x3a, 0xb1, 0x01, 0x92, 0x41, 0xad, 0x01, 0x0a, 0x5b, 0x2a, 0x0e, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x40, 0x43, 0x61, 0x6e, + 0x63, 0x65, 0x6c, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, + 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0xd2, 0x01, 0x06, + 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x32, 0x4e, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, + 0x22, 0x3a, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, + 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, + 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, + 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, + 0x33, 0x37, 0x65, 0x38, 0x22, 0x7d, 0x22, 0xc3, 0x02, 0x0a, 0x19, 0x43, 0x61, 0x6e, 0x63, 0x65, + 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6a, 0x92, 0x41, 0x67, 0x32, 0x53, 0x48, 0x65, 0x78, + 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, + 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, + 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, + 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, + 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x2e, + 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, + 0x34, 0x7d, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x3a, 0x9f, 0x01, 0x92, 0x41, 0x9b, + 0x01, 0x0a, 0x49, 0x2a, 0x0f, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x2d, 0x48, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, + 0x65, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, + 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x2e, 0xd2, 0x01, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x32, 0x4e, 0x7b, 0x22, + 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, + 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, + 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, + 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, + 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x7d, 0x32, 0x8c, 0x03, 0x0a, + 0x0c, 0x44, 0x65, 0x62, 0x75, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x63, 0x0a, + 0x0b, 0x47, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x12, 0x19, 0x2e, 0x64, + 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x12, 0x12, + 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, + 0x67, 0x79, 0x12, 0x85, 0x01, 0x0a, 0x16, 0x47, 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x19, 0x2e, + 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x28, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x12, 0x1e, 0x2f, 0x76, 0x31, 0x2f, + 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x72, + 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x8e, 0x01, 0x0a, 0x11, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x21, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, + 0x52, 0x65, 0x71, 0x1a, 0x26, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2e, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x28, 0x22, 0x26, 0x2f, 0x76, 0x31, 0x2f, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2f, 0x63, + 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x7b, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x7d, 0x42, 0xa1, 0x02, 0x92, 0x41, + 0x71, 0x12, 0x6f, 0x0a, 0x09, 0x44, 0x65, 0x62, 0x75, 0x67, 0x20, 0x41, 0x50, 0x49, 0x2a, 0x55, + 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x36, 0x68, + 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, + 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, + 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, 0x70, + 0x68, 0x61, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, + 0x2e, 0x76, 0x31, 0x42, 0x0d, 0x44, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, + 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x3e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, + 0x69, 0x74, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x64, 0x65, + 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x64, 0x65, 0x62, 0x75, 0x67, 0x61, + 0x70, 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x44, 0x58, 0x58, 0xaa, 0x02, 0x0b, 0x44, 0x65, 0x62, + 0x75, 0x67, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0b, 0x44, 0x65, 0x62, 0x75, 0x67, + 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x17, 0x44, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, + 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0xea, 0x02, 0x0c, 0x44, 0x65, 0x62, 0x75, 0x67, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_debugapi_v1_debugapi_proto_rawDescOnce sync.Once + file_debugapi_v1_debugapi_proto_rawDescData = file_debugapi_v1_debugapi_proto_rawDesc +) + +func file_debugapi_v1_debugapi_proto_rawDescGZIP() []byte { + file_debugapi_v1_debugapi_proto_rawDescOnce.Do(func() { + file_debugapi_v1_debugapi_proto_rawDescData = protoimpl.X.CompressGZIP(file_debugapi_v1_debugapi_proto_rawDescData) + }) + return file_debugapi_v1_debugapi_proto_rawDescData +} + +var file_debugapi_v1_debugapi_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_debugapi_v1_debugapi_proto_goTypes = []interface{}{ + (*EmptyMessage)(nil), // 0: debugapi.v1.EmptyMessage + (*TopologyResponse)(nil), // 1: debugapi.v1.TopologyResponse + (*PendingTransactionsResponse)(nil), // 2: debugapi.v1.PendingTransactionsResponse + (*TransactionInfo)(nil), // 3: debugapi.v1.TransactionInfo + (*CancelTransactionReq)(nil), // 4: debugapi.v1.CancelTransactionReq + (*CancelTransactionResponse)(nil), // 5: debugapi.v1.CancelTransactionResponse + (*structpb.Struct)(nil), // 6: google.protobuf.Struct +} +var file_debugapi_v1_debugapi_proto_depIdxs = []int32{ + 6, // 0: debugapi.v1.TopologyResponse.topology:type_name -> google.protobuf.Struct + 3, // 1: debugapi.v1.PendingTransactionsResponse.pending_transactions:type_name -> debugapi.v1.TransactionInfo + 0, // 2: debugapi.v1.DebugService.GetTopology:input_type -> debugapi.v1.EmptyMessage + 0, // 3: debugapi.v1.DebugService.GetPendingTransactions:input_type -> debugapi.v1.EmptyMessage + 4, // 4: debugapi.v1.DebugService.CancelTransaction:input_type -> debugapi.v1.CancelTransactionReq + 1, // 5: debugapi.v1.DebugService.GetTopology:output_type -> debugapi.v1.TopologyResponse + 2, // 6: debugapi.v1.DebugService.GetPendingTransactions:output_type -> debugapi.v1.PendingTransactionsResponse + 5, // 7: debugapi.v1.DebugService.CancelTransaction:output_type -> debugapi.v1.CancelTransactionResponse + 5, // [5:8] is the sub-list for method output_type + 2, // [2:5] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_debugapi_v1_debugapi_proto_init() } +func file_debugapi_v1_debugapi_proto_init() { + if File_debugapi_v1_debugapi_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_debugapi_v1_debugapi_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*EmptyMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_debugapi_v1_debugapi_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TopologyResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_debugapi_v1_debugapi_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PendingTransactionsResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_debugapi_v1_debugapi_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TransactionInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_debugapi_v1_debugapi_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancelTransactionReq); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_debugapi_v1_debugapi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CancelTransactionResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_debugapi_v1_debugapi_proto_rawDesc, + NumEnums: 0, + NumMessages: 6, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_debugapi_v1_debugapi_proto_goTypes, + DependencyIndexes: file_debugapi_v1_debugapi_proto_depIdxs, + MessageInfos: file_debugapi_v1_debugapi_proto_msgTypes, + }.Build() + File_debugapi_v1_debugapi_proto = out.File + file_debugapi_v1_debugapi_proto_rawDesc = nil + file_debugapi_v1_debugapi_proto_goTypes = nil + file_debugapi_v1_debugapi_proto_depIdxs = nil +} diff --git a/p2p/gen/go/debugapi/v1/debugapi.pb.gw.go b/p2p/gen/go/debugapi/v1/debugapi.pb.gw.go new file mode 100644 index 000000000..c01da47a2 --- /dev/null +++ b/p2p/gen/go/debugapi/v1/debugapi.pb.gw.go @@ -0,0 +1,327 @@ +// Code generated by protoc-gen-grpc-gateway. DO NOT EDIT. +// source: debugapi/v1/debugapi.proto + +/* +Package debugapiv1 is a reverse proxy. + +It translates gRPC into RESTful JSON APIs. +*/ +package debugapiv1 + +import ( + "context" + "io" + "net/http" + + "github.com/grpc-ecosystem/grpc-gateway/v2/runtime" + "github.com/grpc-ecosystem/grpc-gateway/v2/utilities" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/grpclog" + "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/proto" +) + +// Suppress "imported and not used" errors +var _ codes.Code +var _ io.Reader +var _ status.Status +var _ = runtime.String +var _ = utilities.NewDoubleArray +var _ = metadata.Join + +func request_DebugService_GetTopology_0(ctx context.Context, marshaler runtime.Marshaler, client DebugServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq EmptyMessage + var metadata runtime.ServerMetadata + + msg, err := client.GetTopology(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DebugService_GetTopology_0(ctx context.Context, marshaler runtime.Marshaler, server DebugServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq EmptyMessage + var metadata runtime.ServerMetadata + + msg, err := server.GetTopology(ctx, &protoReq) + return msg, metadata, err + +} + +func request_DebugService_GetPendingTransactions_0(ctx context.Context, marshaler runtime.Marshaler, client DebugServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq EmptyMessage + var metadata runtime.ServerMetadata + + msg, err := client.GetPendingTransactions(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DebugService_GetPendingTransactions_0(ctx context.Context, marshaler runtime.Marshaler, server DebugServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq EmptyMessage + var metadata runtime.ServerMetadata + + msg, err := server.GetPendingTransactions(ctx, &protoReq) + return msg, metadata, err + +} + +func request_DebugService_CancelTransaction_0(ctx context.Context, marshaler runtime.Marshaler, client DebugServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CancelTransactionReq + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["tx_hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") + } + + protoReq.TxHash, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) + } + + msg, err := client.CancelTransaction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_DebugService_CancelTransaction_0(ctx context.Context, marshaler runtime.Marshaler, server DebugServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq CancelTransactionReq + var metadata runtime.ServerMetadata + + var ( + val string + ok bool + err error + _ = err + ) + + val, ok = pathParams["tx_hash"] + if !ok { + return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") + } + + protoReq.TxHash, err = runtime.String(val) + if err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) + } + + msg, err := server.CancelTransaction(ctx, &protoReq) + return msg, metadata, err + +} + +// RegisterDebugServiceHandlerServer registers the http handlers for service DebugService to "mux". +// UnaryRPC :call DebugServiceServer directly. +// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. +// Note that using this registration option will cause many gRPC library features to stop working. Consider using RegisterDebugServiceHandlerFromEndpoint instead. +func RegisterDebugServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server DebugServiceServer) error { + + mux.Handle("GET", pattern_DebugService_GetTopology_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/debugapi.v1.DebugService/GetTopology", runtime.WithHTTPPathPattern("/v1/debug/topology")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DebugService_GetTopology_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_GetTopology_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_DebugService_GetPendingTransactions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/debugapi.v1.DebugService/GetPendingTransactions", runtime.WithHTTPPathPattern("/v1/debug/pending_transactions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DebugService_GetPendingTransactions_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_GetPendingTransactions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_DebugService_CancelTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/debugapi.v1.DebugService/CancelTransaction", runtime.WithHTTPPathPattern("/v1/debug/cancel_transaction/{tx_hash}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_DebugService_CancelTransaction_0(annotatedContext, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_CancelTransaction_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +// RegisterDebugServiceHandlerFromEndpoint is same as RegisterDebugServiceHandler but +// automatically dials to "endpoint" and closes the connection when "ctx" gets done. +func RegisterDebugServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { + conn, err := grpc.NewClient(endpoint, opts...) + if err != nil { + return err + } + defer func() { + if err != nil { + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + return + } + go func() { + <-ctx.Done() + if cerr := conn.Close(); cerr != nil { + grpclog.Errorf("Failed to close conn to %s: %v", endpoint, cerr) + } + }() + }() + + return RegisterDebugServiceHandler(ctx, mux, conn) +} + +// RegisterDebugServiceHandler registers the http handlers for service DebugService to "mux". +// The handlers forward requests to the grpc endpoint over "conn". +func RegisterDebugServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error { + return RegisterDebugServiceHandlerClient(ctx, mux, NewDebugServiceClient(conn)) +} + +// RegisterDebugServiceHandlerClient registers the http handlers for service DebugService +// to "mux". The handlers forward requests to the grpc endpoint over the given implementation of "DebugServiceClient". +// Note: the gRPC framework executes interceptors within the gRPC handler. If the passed in "DebugServiceClient" +// doesn't go through the normal gRPC flow (creating a gRPC client etc.) then it will be up to the passed in +// "DebugServiceClient" to call the correct interceptors. +func RegisterDebugServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client DebugServiceClient) error { + + mux.Handle("GET", pattern_DebugService_GetTopology_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/debugapi.v1.DebugService/GetTopology", runtime.WithHTTPPathPattern("/v1/debug/topology")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DebugService_GetTopology_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_GetTopology_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_DebugService_GetPendingTransactions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/debugapi.v1.DebugService/GetPendingTransactions", runtime.WithHTTPPathPattern("/v1/debug/pending_transactions")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DebugService_GetPendingTransactions_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_GetPendingTransactions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("POST", pattern_DebugService_CancelTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + var err error + var annotatedContext context.Context + annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/debugapi.v1.DebugService/CancelTransaction", runtime.WithHTTPPathPattern("/v1/debug/cancel_transaction/{tx_hash}")) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_DebugService_CancelTransaction_0(annotatedContext, inboundMarshaler, client, req, pathParams) + annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) + if err != nil { + runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) + return + } + + forward_DebugService_CancelTransaction_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + return nil +} + +var ( + pattern_DebugService_GetTopology_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "debug", "topology"}, "")) + + pattern_DebugService_GetPendingTransactions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "debug", "pending_transactions"}, "")) + + pattern_DebugService_CancelTransaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "debug", "cancel_transaction", "tx_hash"}, "")) +) + +var ( + forward_DebugService_GetTopology_0 = runtime.ForwardResponseMessage + + forward_DebugService_GetPendingTransactions_0 = runtime.ForwardResponseMessage + + forward_DebugService_CancelTransaction_0 = runtime.ForwardResponseMessage +) diff --git a/p2p/gen/go/debugapi/v1/debugapi_grpc.pb.go b/p2p/gen/go/debugapi/v1/debugapi_grpc.pb.go new file mode 100644 index 000000000..3c3f4715a --- /dev/null +++ b/p2p/gen/go/debugapi/v1/debugapi_grpc.pb.go @@ -0,0 +1,203 @@ +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc (unknown) +// source: debugapi/v1/debugapi.proto + +package debugapiv1 + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + DebugService_GetTopology_FullMethodName = "/debugapi.v1.DebugService/GetTopology" + DebugService_GetPendingTransactions_FullMethodName = "/debugapi.v1.DebugService/GetPendingTransactions" + DebugService_CancelTransaction_FullMethodName = "/debugapi.v1.DebugService/CancelTransaction" +) + +// DebugServiceClient is the client API for DebugService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. +type DebugServiceClient interface { + // GetTopology + // + // GetTopology is called by the user to get the topology of the node. The topology + // includes connectivity information about the node. + GetTopology(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*TopologyResponse, error) + // GetPendingTransactions + // + // GetPendingTransactions is called by the provider to get the pending transactions for the wallet. + GetPendingTransactions(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PendingTransactionsResponse, error) + // CancelTransaction + // + // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. + CancelTransaction(ctx context.Context, in *CancelTransactionReq, opts ...grpc.CallOption) (*CancelTransactionResponse, error) +} + +type debugServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDebugServiceClient(cc grpc.ClientConnInterface) DebugServiceClient { + return &debugServiceClient{cc} +} + +func (c *debugServiceClient) GetTopology(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*TopologyResponse, error) { + out := new(TopologyResponse) + err := c.cc.Invoke(ctx, DebugService_GetTopology_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugServiceClient) GetPendingTransactions(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PendingTransactionsResponse, error) { + out := new(PendingTransactionsResponse) + err := c.cc.Invoke(ctx, DebugService_GetPendingTransactions_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *debugServiceClient) CancelTransaction(ctx context.Context, in *CancelTransactionReq, opts ...grpc.CallOption) (*CancelTransactionResponse, error) { + out := new(CancelTransactionResponse) + err := c.cc.Invoke(ctx, DebugService_CancelTransaction_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DebugServiceServer is the server API for DebugService service. +// All implementations must embed UnimplementedDebugServiceServer +// for forward compatibility +type DebugServiceServer interface { + // GetTopology + // + // GetTopology is called by the user to get the topology of the node. The topology + // includes connectivity information about the node. + GetTopology(context.Context, *EmptyMessage) (*TopologyResponse, error) + // GetPendingTransactions + // + // GetPendingTransactions is called by the provider to get the pending transactions for the wallet. + GetPendingTransactions(context.Context, *EmptyMessage) (*PendingTransactionsResponse, error) + // CancelTransaction + // + // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. + CancelTransaction(context.Context, *CancelTransactionReq) (*CancelTransactionResponse, error) + mustEmbedUnimplementedDebugServiceServer() +} + +// UnimplementedDebugServiceServer must be embedded to have forward compatible implementations. +type UnimplementedDebugServiceServer struct { +} + +func (UnimplementedDebugServiceServer) GetTopology(context.Context, *EmptyMessage) (*TopologyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetTopology not implemented") +} +func (UnimplementedDebugServiceServer) GetPendingTransactions(context.Context, *EmptyMessage) (*PendingTransactionsResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetPendingTransactions not implemented") +} +func (UnimplementedDebugServiceServer) CancelTransaction(context.Context, *CancelTransactionReq) (*CancelTransactionResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method CancelTransaction not implemented") +} +func (UnimplementedDebugServiceServer) mustEmbedUnimplementedDebugServiceServer() {} + +// UnsafeDebugServiceServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to DebugServiceServer will +// result in compilation errors. +type UnsafeDebugServiceServer interface { + mustEmbedUnimplementedDebugServiceServer() +} + +func RegisterDebugServiceServer(s grpc.ServiceRegistrar, srv DebugServiceServer) { + s.RegisterService(&DebugService_ServiceDesc, srv) +} + +func _DebugService_GetTopology_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EmptyMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServiceServer).GetTopology(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DebugService_GetTopology_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServiceServer).GetTopology(ctx, req.(*EmptyMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _DebugService_GetPendingTransactions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(EmptyMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServiceServer).GetPendingTransactions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DebugService_GetPendingTransactions_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServiceServer).GetPendingTransactions(ctx, req.(*EmptyMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _DebugService_CancelTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(CancelTransactionReq) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DebugServiceServer).CancelTransaction(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: DebugService_CancelTransaction_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DebugServiceServer).CancelTransaction(ctx, req.(*CancelTransactionReq)) + } + return interceptor(ctx, in, info, handler) +} + +// DebugService_ServiceDesc is the grpc.ServiceDesc for DebugService service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var DebugService_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "debugapi.v1.DebugService", + HandlerType: (*DebugServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "GetTopology", + Handler: _DebugService_GetTopology_Handler, + }, + { + MethodName: "GetPendingTransactions", + Handler: _DebugService_GetPendingTransactions_Handler, + }, + { + MethodName: "CancelTransaction", + Handler: _DebugService_CancelTransaction_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "debugapi/v1/debugapi.proto", +} diff --git a/p2p/gen/go/providerapi/v1/providerapi.pb.go b/p2p/gen/go/providerapi/v1/providerapi.pb.go index 55ce9df38..e982d6a7e 100644 --- a/p2p/gen/go/providerapi/v1/providerapi.pb.go +++ b/p2p/gen/go/providerapi/v1/providerapi.pb.go @@ -354,210 +354,6 @@ func (x *BidResponse) GetDispatchTimestamp() int64 { return 0 } -type PendingTxnsResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - PendingTxns []*TransactionInfo `protobuf:"bytes,1,rep,name=pending_txns,json=pendingTxns,proto3" json:"pending_txns,omitempty"` -} - -func (x *PendingTxnsResponse) Reset() { - *x = PendingTxnsResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *PendingTxnsResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*PendingTxnsResponse) ProtoMessage() {} - -func (x *PendingTxnsResponse) ProtoReflect() protoreflect.Message { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use PendingTxnsResponse.ProtoReflect.Descriptor instead. -func (*PendingTxnsResponse) Descriptor() ([]byte, []int) { - return file_providerapi_v1_providerapi_proto_rawDescGZIP(), []int{5} -} - -func (x *PendingTxnsResponse) GetPendingTxns() []*TransactionInfo { - if x != nil { - return x.PendingTxns - } - return nil -} - -type TransactionInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` - Nonce int64 `protobuf:"varint,2,opt,name=nonce,proto3" json:"nonce,omitempty"` - Created string `protobuf:"bytes,3,opt,name=created,proto3" json:"created,omitempty"` -} - -func (x *TransactionInfo) Reset() { - *x = TransactionInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[6] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *TransactionInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*TransactionInfo) ProtoMessage() {} - -func (x *TransactionInfo) ProtoReflect() protoreflect.Message { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[6] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use TransactionInfo.ProtoReflect.Descriptor instead. -func (*TransactionInfo) Descriptor() ([]byte, []int) { - return file_providerapi_v1_providerapi_proto_rawDescGZIP(), []int{6} -} - -func (x *TransactionInfo) GetTxHash() string { - if x != nil { - return x.TxHash - } - return "" -} - -func (x *TransactionInfo) GetNonce() int64 { - if x != nil { - return x.Nonce - } - return 0 -} - -func (x *TransactionInfo) GetCreated() string { - if x != nil { - return x.Created - } - return "" -} - -type CancelReq struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` -} - -func (x *CancelReq) Reset() { - *x = CancelReq{} - if protoimpl.UnsafeEnabled { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[7] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CancelReq) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CancelReq) ProtoMessage() {} - -func (x *CancelReq) ProtoReflect() protoreflect.Message { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[7] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CancelReq.ProtoReflect.Descriptor instead. -func (*CancelReq) Descriptor() ([]byte, []int) { - return file_providerapi_v1_providerapi_proto_rawDescGZIP(), []int{7} -} - -func (x *CancelReq) GetTxHash() string { - if x != nil { - return x.TxHash - } - return "" -} - -type CancelResponse struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TxHash string `protobuf:"bytes,1,opt,name=tx_hash,json=txHash,proto3" json:"tx_hash,omitempty"` -} - -func (x *CancelResponse) Reset() { - *x = CancelResponse{} - if protoimpl.UnsafeEnabled { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[8] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CancelResponse) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CancelResponse) ProtoMessage() {} - -func (x *CancelResponse) ProtoReflect() protoreflect.Message { - mi := &file_providerapi_v1_providerapi_proto_msgTypes[8] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use CancelResponse.ProtoReflect.Descriptor instead. -func (*CancelResponse) Descriptor() ([]byte, []int) { - return file_providerapi_v1_providerapi_proto_rawDescGZIP(), []int{8} -} - -func (x *CancelResponse) GetTxHash() string { - if x != nil { - return x.TxHash - } - return "" -} - var File_providerapi_v1_providerapi_proto protoreflect.FileDescriptor var file_providerapi_v1_providerapi_proto_rawDesc = []byte{ @@ -750,169 +546,63 @@ var file_providerapi_v1_providerapi_proto_rawDesc = []byte{ 0x5f, 0x41, 0x43, 0x43, 0x45, 0x50, 0x54, 0x45, 0x44, 0x22, 0x2c, 0x20, 0x22, 0x64, 0x65, 0x63, 0x61, 0x79, 0x44, 0x69, 0x73, 0x70, 0x61, 0x74, 0x63, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, - 0x7d, 0x22, 0xfc, 0x01, 0x0a, 0x13, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x6e, - 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x0c, 0x70, 0x65, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, - 0x31, 0x2e, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, - 0x6f, 0x42, 0x44, 0x92, 0x41, 0x41, 0x32, 0x3f, 0x4c, 0x69, 0x73, 0x74, 0x20, 0x6f, 0x66, 0x20, - 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x5f, 0x72, 0x65, - 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x2e, 0x52, 0x0b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, - 0x54, 0x78, 0x6e, 0x73, 0x3a, 0x5a, 0x92, 0x41, 0x57, 0x0a, 0x55, 0x2a, 0x19, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x20, 0x6c, 0x69, 0x73, 0x74, 0x32, 0x2a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x2e, 0xd2, 0x01, 0x0b, 0x70, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x6e, 0x73, - 0x22, 0xa5, 0x04, 0x0a, 0x0f, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, - 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x91, 0x01, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x78, 0x92, 0x41, 0x75, 0x32, 0x61, 0x48, 0x65, 0x78, - 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, - 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, - 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x8a, 0x01, - 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, - 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x12, 0x3a, 0x0a, 0x05, 0x6e, 0x6f, 0x6e, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x42, 0x24, 0x92, 0x41, 0x21, 0x32, 0x1f, 0x4e, 0x6f, - 0x6e, 0x63, 0x65, 0x20, 0x75, 0x73, 0x65, 0x64, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x05, 0x6e, - 0x6f, 0x6e, 0x63, 0x65, 0x12, 0x45, 0x0a, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x2b, 0x92, 0x41, 0x28, 0x32, 0x26, 0x54, 0x69, 0x6d, 0x65, - 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x61, 0x73, 0x20, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x2e, 0x52, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x3a, 0xfa, 0x01, 0x92, 0x41, - 0xf6, 0x01, 0x0a, 0x59, 0x2a, 0x10, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x32, 0x2a, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x66, 0x6f, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x65, - 0x64, 0x20, 0x62, 0x79, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x2e, 0xd2, 0x01, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0xd2, 0x01, 0x05, 0x6e, 0x6f, - 0x6e, 0x63, 0x65, 0xd2, 0x01, 0x07, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x32, 0x98, 0x01, - 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x37, 0x31, 0x63, 0x31, - 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, 0x38, 0x31, 0x34, 0x66, 0x39, - 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, 0x34, 0x33, 0x35, 0x65, 0x61, - 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, 0x61, 0x63, 0x34, 0x38, 0x38, - 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, 0x38, 0x22, 0x2c, 0x20, 0x22, - 0x6e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x20, 0x31, 0x32, 0x33, 0x34, 0x2c, 0x20, 0x22, 0x63, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x22, 0x3a, 0x20, 0x22, 0x32, 0x30, 0x30, 0x39, 0x2d, 0x31, - 0x31, 0x2d, 0x31, 0x30, 0x20, 0x32, 0x33, 0x3a, 0x30, 0x30, 0x3a, 0x30, 0x30, 0x20, 0x2b, 0x30, - 0x30, 0x30, 0x30, 0x20, 0x55, 0x54, 0x43, 0x20, 0x6d, 0x3d, 0x2b, 0x30, 0x2e, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x22, 0x7d, 0x22, 0xad, 0x02, 0x0a, 0x09, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x12, 0x83, 0x01, 0x0a, 0x07, 0x74, 0x78, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6a, 0x92, 0x41, 0x67, 0x32, 0x53, 0x48, - 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, - 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x68, 0x20, 0x6f, - 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x69, 0x64, 0x64, 0x65, - 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, 0x46, 0x30, 0x2d, 0x39, 0x5d, - 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x3a, 0x99, 0x01, 0x92, - 0x41, 0x95, 0x01, 0x0a, 0x5b, 0x2a, 0x0e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x20, 0x72, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x32, 0x40, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x20, 0x74, 0x72, - 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x20, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x62, - 0x69, 0x64, 0x64, 0x65, 0x72, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2e, 0xd2, 0x01, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, - 0x32, 0x36, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x20, 0x22, 0x39, 0x31, - 0x61, 0x38, 0x39, 0x42, 0x36, 0x33, 0x33, 0x31, 0x39, 0x34, 0x63, 0x30, 0x44, 0x38, 0x36, 0x43, - 0x35, 0x33, 0x39, 0x41, 0x31, 0x41, 0x35, 0x42, 0x31, 0x34, 0x44, 0x43, 0x43, 0x61, 0x63, 0x66, - 0x44, 0x34, 0x37, 0x30, 0x39, 0x34, 0x22, 0x7d, 0x22, 0xb8, 0x02, 0x0a, 0x0e, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x83, 0x01, 0x0a, 0x07, - 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x6a, 0x92, - 0x41, 0x67, 0x32, 0x53, 0x48, 0x65, 0x78, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x20, 0x65, - 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x68, - 0x61, 0x73, 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, - 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, - 0x62, 0x69, 0x64, 0x64, 0x65, 0x72, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x73, 0x20, 0x74, 0x6f, 0x20, - 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x2e, 0x8a, 0x01, 0x0f, 0x5b, 0x61, 0x2d, 0x66, 0x41, 0x2d, - 0x46, 0x30, 0x2d, 0x39, 0x5d, 0x7b, 0x36, 0x34, 0x7d, 0x52, 0x06, 0x74, 0x78, 0x48, 0x61, 0x73, - 0x68, 0x3a, 0x9f, 0x01, 0x92, 0x41, 0x9b, 0x01, 0x0a, 0x49, 0x2a, 0x0f, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x2d, 0x48, 0x61, 0x73, - 0x68, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0xd2, 0x01, 0x06, 0x74, 0x78, 0x48, - 0x61, 0x73, 0x68, 0x32, 0x4e, 0x7b, 0x22, 0x74, 0x78, 0x48, 0x61, 0x73, 0x68, 0x22, 0x3a, 0x20, - 0x22, 0x37, 0x31, 0x63, 0x31, 0x33, 0x34, 0x38, 0x66, 0x32, 0x64, 0x37, 0x66, 0x66, 0x37, 0x65, - 0x38, 0x31, 0x34, 0x66, 0x39, 0x63, 0x33, 0x36, 0x31, 0x37, 0x39, 0x38, 0x33, 0x37, 0x30, 0x33, - 0x34, 0x33, 0x35, 0x65, 0x61, 0x37, 0x34, 0x34, 0x36, 0x64, 0x65, 0x34, 0x32, 0x30, 0x61, 0x65, - 0x61, 0x63, 0x34, 0x38, 0x38, 0x62, 0x66, 0x31, 0x64, 0x65, 0x33, 0x35, 0x37, 0x33, 0x37, 0x65, - 0x38, 0x22, 0x7d, 0x32, 0xc5, 0x06, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x12, 0x65, 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x42, 0x69, 0x64, 0x73, 0x12, - 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, - 0x69, 0x64, 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, - 0x5f, 0x62, 0x69, 0x64, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x50, - 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x42, 0x69, 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, - 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, - 0x01, 0x2a, 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x2f, 0x73, 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, - 0x62, 0x69, 0x64, 0x73, 0x28, 0x01, 0x12, 0x7a, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, - 0x65, 0x72, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, - 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, - 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x24, 0x2f, 0x76, - 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, - 0x74, 0x65, 0x72, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, - 0x74, 0x7d, 0x12, 0x67, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, - 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, - 0x93, 0x02, 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, - 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x6e, 0x0a, 0x0b, 0x47, - 0x65, 0x74, 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, - 0x1a, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, - 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x7a, 0x0a, 0x0e, 0x47, - 0x65, 0x74, 0x50, 0x65, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x6e, 0x73, 0x12, 0x1c, 0x2e, + 0x7d, 0x32, 0xc5, 0x04, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x65, + 0x0a, 0x0b, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x42, 0x69, 0x64, 0x73, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x23, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x65, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x54, 0x78, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x12, 0x1d, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, 0x70, 0x65, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x5f, 0x74, 0x78, 0x6e, 0x73, 0x12, 0x81, 0x01, 0x0a, 0x11, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x1a, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, - 0x22, 0x29, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x63, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x7b, 0x74, 0x78, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x7d, 0x42, 0xbc, 0x02, 0x92, 0x41, - 0x74, 0x12, 0x72, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, - 0x49, 0x2a, 0x55, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, - 0x12, 0x36, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, - 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, - 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, - 0x61, 0x6c, 0x70, 0x68, 0x61, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, - 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, - 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x70, 0x32, 0x70, 0x2f, - 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, - 0x70, 0x69, 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, - 0x69, 0x76, 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0e, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1a, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x13, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, + 0x22, 0x21, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1b, 0x12, 0x19, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x5f, 0x62, + 0x69, 0x64, 0x73, 0x30, 0x01, 0x12, 0x7d, 0x0a, 0x11, 0x53, 0x65, 0x6e, 0x64, 0x50, 0x72, 0x6f, + 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x42, 0x69, 0x64, 0x73, 0x12, 0x1b, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x69, 0x64, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x1a, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x25, 0x3a, 0x01, 0x2a, + 0x22, 0x20, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x73, + 0x65, 0x6e, 0x64, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x5f, 0x62, 0x69, + 0x64, 0x73, 0x28, 0x01, 0x12, 0x7a, 0x0a, 0x0d, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, + 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x26, 0x22, 0x24, 0x2f, 0x76, 0x31, 0x2f, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, + 0x72, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x2f, 0x7b, 0x61, 0x6d, 0x6f, 0x75, 0x6e, 0x74, 0x7d, + 0x12, 0x67, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, + 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x18, 0x12, 0x16, 0x2f, 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, + 0x67, 0x65, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x6e, 0x0a, 0x0b, 0x47, 0x65, 0x74, + 0x4d, 0x69, 0x6e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x12, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x4d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x6b, 0x65, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x22, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1c, 0x12, 0x1a, 0x2f, + 0x76, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x2f, 0x67, 0x65, 0x74, 0x5f, + 0x6d, 0x69, 0x6e, 0x5f, 0x73, 0x74, 0x61, 0x6b, 0x65, 0x42, 0xbc, 0x02, 0x92, 0x41, 0x74, 0x12, + 0x72, 0x0a, 0x0c, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x20, 0x41, 0x50, 0x49, 0x2a, + 0x55, 0x0a, 0x1b, 0x42, 0x75, 0x73, 0x69, 0x6e, 0x65, 0x73, 0x73, 0x20, 0x53, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x20, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x31, 0x2e, 0x31, 0x12, 0x36, + 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, 0x65, 0x76, 0x2d, 0x63, 0x6f, + 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, + 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x0b, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2d, 0x61, 0x6c, + 0x70, 0x68, 0x61, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x42, 0x10, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x44, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x70, 0x72, 0x69, 0x6d, 0x65, 0x76, 0x2f, 0x6d, + 0x65, 0x76, 0x2d, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x2f, 0x70, 0x32, 0x70, 0x2f, 0x67, 0x65, + 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, + 0x2f, 0x76, 0x31, 0x3b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x76, + 0x31, 0xa2, 0x02, 0x03, 0x50, 0x58, 0x58, 0xaa, 0x02, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x61, 0x70, 0x69, 0x2e, 0x56, 0x31, 0xca, 0x02, 0x0e, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0xe2, 0x02, 0x1a, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x61, 0x70, 0x69, 0x5c, 0x56, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x61, 0x70, 0x69, 0x3a, 0x3a, 0x56, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -928,41 +618,32 @@ func file_providerapi_v1_providerapi_proto_rawDescGZIP() []byte { } var file_providerapi_v1_providerapi_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_providerapi_v1_providerapi_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_providerapi_v1_providerapi_proto_msgTypes = make([]protoimpl.MessageInfo, 5) var file_providerapi_v1_providerapi_proto_goTypes = []interface{}{ - (BidResponse_Status)(0), // 0: providerapi.v1.BidResponse.Status - (*StakeRequest)(nil), // 1: providerapi.v1.StakeRequest - (*StakeResponse)(nil), // 2: providerapi.v1.StakeResponse - (*EmptyMessage)(nil), // 3: providerapi.v1.EmptyMessage - (*Bid)(nil), // 4: providerapi.v1.Bid - (*BidResponse)(nil), // 5: providerapi.v1.BidResponse - (*PendingTxnsResponse)(nil), // 6: providerapi.v1.PendingTxnsResponse - (*TransactionInfo)(nil), // 7: providerapi.v1.TransactionInfo - (*CancelReq)(nil), // 8: providerapi.v1.CancelReq - (*CancelResponse)(nil), // 9: providerapi.v1.CancelResponse + (BidResponse_Status)(0), // 0: providerapi.v1.BidResponse.Status + (*StakeRequest)(nil), // 1: providerapi.v1.StakeRequest + (*StakeResponse)(nil), // 2: providerapi.v1.StakeResponse + (*EmptyMessage)(nil), // 3: providerapi.v1.EmptyMessage + (*Bid)(nil), // 4: providerapi.v1.Bid + (*BidResponse)(nil), // 5: providerapi.v1.BidResponse } var file_providerapi_v1_providerapi_proto_depIdxs = []int32{ 0, // 0: providerapi.v1.BidResponse.status:type_name -> providerapi.v1.BidResponse.Status - 7, // 1: providerapi.v1.PendingTxnsResponse.pending_txns:type_name -> providerapi.v1.TransactionInfo - 3, // 2: providerapi.v1.Provider.ReceiveBids:input_type -> providerapi.v1.EmptyMessage - 5, // 3: providerapi.v1.Provider.SendProcessedBids:input_type -> providerapi.v1.BidResponse - 1, // 4: providerapi.v1.Provider.RegisterStake:input_type -> providerapi.v1.StakeRequest - 3, // 5: providerapi.v1.Provider.GetStake:input_type -> providerapi.v1.EmptyMessage - 3, // 6: providerapi.v1.Provider.GetMinStake:input_type -> providerapi.v1.EmptyMessage - 3, // 7: providerapi.v1.Provider.GetPendingTxns:input_type -> providerapi.v1.EmptyMessage - 8, // 8: providerapi.v1.Provider.CancelTransaction:input_type -> providerapi.v1.CancelReq - 4, // 9: providerapi.v1.Provider.ReceiveBids:output_type -> providerapi.v1.Bid - 3, // 10: providerapi.v1.Provider.SendProcessedBids:output_type -> providerapi.v1.EmptyMessage - 2, // 11: providerapi.v1.Provider.RegisterStake:output_type -> providerapi.v1.StakeResponse - 2, // 12: providerapi.v1.Provider.GetStake:output_type -> providerapi.v1.StakeResponse - 2, // 13: providerapi.v1.Provider.GetMinStake:output_type -> providerapi.v1.StakeResponse - 6, // 14: providerapi.v1.Provider.GetPendingTxns:output_type -> providerapi.v1.PendingTxnsResponse - 9, // 15: providerapi.v1.Provider.CancelTransaction:output_type -> providerapi.v1.CancelResponse - 9, // [9:16] is the sub-list for method output_type - 2, // [2:9] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 3, // 1: providerapi.v1.Provider.ReceiveBids:input_type -> providerapi.v1.EmptyMessage + 5, // 2: providerapi.v1.Provider.SendProcessedBids:input_type -> providerapi.v1.BidResponse + 1, // 3: providerapi.v1.Provider.RegisterStake:input_type -> providerapi.v1.StakeRequest + 3, // 4: providerapi.v1.Provider.GetStake:input_type -> providerapi.v1.EmptyMessage + 3, // 5: providerapi.v1.Provider.GetMinStake:input_type -> providerapi.v1.EmptyMessage + 4, // 6: providerapi.v1.Provider.ReceiveBids:output_type -> providerapi.v1.Bid + 3, // 7: providerapi.v1.Provider.SendProcessedBids:output_type -> providerapi.v1.EmptyMessage + 2, // 8: providerapi.v1.Provider.RegisterStake:output_type -> providerapi.v1.StakeResponse + 2, // 9: providerapi.v1.Provider.GetStake:output_type -> providerapi.v1.StakeResponse + 2, // 10: providerapi.v1.Provider.GetMinStake:output_type -> providerapi.v1.StakeResponse + 6, // [6:11] is the sub-list for method output_type + 1, // [1:6] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name } func init() { file_providerapi_v1_providerapi_proto_init() } @@ -1031,54 +712,6 @@ func file_providerapi_v1_providerapi_proto_init() { return nil } } - file_providerapi_v1_providerapi_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PendingTxnsResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_providerapi_v1_providerapi_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TransactionInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_providerapi_v1_providerapi_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelReq); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_providerapi_v1_providerapi_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelResponse); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -1086,7 +719,7 @@ func file_providerapi_v1_providerapi_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_providerapi_v1_providerapi_proto_rawDesc, NumEnums: 1, - NumMessages: 9, + NumMessages: 5, NumExtensions: 0, NumServices: 1, }, diff --git a/p2p/gen/go/providerapi/v1/providerapi.pb.gw.go b/p2p/gen/go/providerapi/v1/providerapi.pb.gw.go index 0b791d9fd..e4b679b7b 100644 --- a/p2p/gen/go/providerapi/v1/providerapi.pb.gw.go +++ b/p2p/gen/go/providerapi/v1/providerapi.pb.gw.go @@ -180,76 +180,6 @@ func local_request_Provider_GetMinStake_0(ctx context.Context, marshaler runtime } -func request_Provider_GetPendingTxns_0(ctx context.Context, marshaler runtime.Marshaler, client ProviderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq EmptyMessage - var metadata runtime.ServerMetadata - - msg, err := client.GetPendingTxns(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Provider_GetPendingTxns_0(ctx context.Context, marshaler runtime.Marshaler, server ProviderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq EmptyMessage - var metadata runtime.ServerMetadata - - msg, err := server.GetPendingTxns(ctx, &protoReq) - return msg, metadata, err - -} - -func request_Provider_CancelTransaction_0(ctx context.Context, marshaler runtime.Marshaler, client ProviderClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq CancelReq - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["tx_hash"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") - } - - protoReq.TxHash, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) - } - - msg, err := client.CancelTransaction(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_Provider_CancelTransaction_0(ctx context.Context, marshaler runtime.Marshaler, server ProviderServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq CancelReq - var metadata runtime.ServerMetadata - - var ( - val string - ok bool - err error - _ = err - ) - - val, ok = pathParams["tx_hash"] - if !ok { - return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "tx_hash") - } - - protoReq.TxHash, err = runtime.String(val) - if err != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "tx_hash", err) - } - - msg, err := server.CancelTransaction(ctx, &protoReq) - return msg, metadata, err - -} - // RegisterProviderHandlerServer registers the http handlers for service Provider to "mux". // UnaryRPC :call ProviderServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -345,56 +275,6 @@ func RegisterProviderHandlerServer(ctx context.Context, mux *runtime.ServeMux, s }) - mux.Handle("GET", pattern_Provider_GetPendingTxns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/providerapi.v1.Provider/GetPendingTxns", runtime.WithHTTPPathPattern("/v1/provider/get_pending_txns")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Provider_GetPendingTxns_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Provider_GetPendingTxns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_Provider_CancelTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - var stream runtime.ServerTransportStream - ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/providerapi.v1.Provider/CancelTransaction", runtime.WithHTTPPathPattern("/v1/provider/cancel_transaction/{tx_hash}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_Provider_CancelTransaction_0(annotatedContext, inboundMarshaler, server, req, pathParams) - md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Provider_CancelTransaction_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -546,50 +426,6 @@ func RegisterProviderHandlerClient(ctx context.Context, mux *runtime.ServeMux, c }) - mux.Handle("GET", pattern_Provider_GetPendingTxns_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/providerapi.v1.Provider/GetPendingTxns", runtime.WithHTTPPathPattern("/v1/provider/get_pending_txns")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Provider_GetPendingTxns_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Provider_GetPendingTxns_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_Provider_CancelTransaction_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - var err error - var annotatedContext context.Context - annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/providerapi.v1.Provider/CancelTransaction", runtime.WithHTTPPathPattern("/v1/provider/cancel_transaction/{tx_hash}")) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_Provider_CancelTransaction_0(annotatedContext, inboundMarshaler, client, req, pathParams) - annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md) - if err != nil { - runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err) - return - } - - forward_Provider_CancelTransaction_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - return nil } @@ -603,10 +439,6 @@ var ( pattern_Provider_GetStake_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "provider", "get_stake"}, "")) pattern_Provider_GetMinStake_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "provider", "get_min_stake"}, "")) - - pattern_Provider_GetPendingTxns_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "provider", "get_pending_txns"}, "")) - - pattern_Provider_CancelTransaction_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "provider", "cancel_transaction", "tx_hash"}, "")) ) var ( @@ -619,8 +451,4 @@ var ( forward_Provider_GetStake_0 = runtime.ForwardResponseMessage forward_Provider_GetMinStake_0 = runtime.ForwardResponseMessage - - forward_Provider_GetPendingTxns_0 = runtime.ForwardResponseMessage - - forward_Provider_CancelTransaction_0 = runtime.ForwardResponseMessage ) diff --git a/p2p/gen/go/providerapi/v1/providerapi_grpc.pb.go b/p2p/gen/go/providerapi/v1/providerapi_grpc.pb.go index 006471e06..89df1e169 100644 --- a/p2p/gen/go/providerapi/v1/providerapi_grpc.pb.go +++ b/p2p/gen/go/providerapi/v1/providerapi_grpc.pb.go @@ -24,8 +24,6 @@ const ( Provider_RegisterStake_FullMethodName = "/providerapi.v1.Provider/RegisterStake" Provider_GetStake_FullMethodName = "/providerapi.v1.Provider/GetStake" Provider_GetMinStake_FullMethodName = "/providerapi.v1.Provider/GetMinStake" - Provider_GetPendingTxns_FullMethodName = "/providerapi.v1.Provider/GetPendingTxns" - Provider_CancelTransaction_FullMethodName = "/providerapi.v1.Provider/CancelTransaction" ) // ProviderClient is the client API for Provider service. @@ -54,14 +52,6 @@ type ProviderClient interface { // // GetMinStake is called by the provider to get the minimum stake required to be in the provider registry. GetMinStake(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*StakeResponse, error) - // GetPendingTxns - // - // GetPendingTxns is called by the provider to get the pending transactions for the wallet. - GetPendingTxns(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PendingTxnsResponse, error) - // CancelTransaction - // - // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. - CancelTransaction(ctx context.Context, in *CancelReq, opts ...grpc.CallOption) (*CancelResponse, error) } type providerClient struct { @@ -165,24 +155,6 @@ func (c *providerClient) GetMinStake(ctx context.Context, in *EmptyMessage, opts return out, nil } -func (c *providerClient) GetPendingTxns(ctx context.Context, in *EmptyMessage, opts ...grpc.CallOption) (*PendingTxnsResponse, error) { - out := new(PendingTxnsResponse) - err := c.cc.Invoke(ctx, Provider_GetPendingTxns_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - -func (c *providerClient) CancelTransaction(ctx context.Context, in *CancelReq, opts ...grpc.CallOption) (*CancelResponse, error) { - out := new(CancelResponse) - err := c.cc.Invoke(ctx, Provider_CancelTransaction_FullMethodName, in, out, opts...) - if err != nil { - return nil, err - } - return out, nil -} - // ProviderServer is the server API for Provider service. // All implementations must embed UnimplementedProviderServer // for forward compatibility @@ -209,14 +181,6 @@ type ProviderServer interface { // // GetMinStake is called by the provider to get the minimum stake required to be in the provider registry. GetMinStake(context.Context, *EmptyMessage) (*StakeResponse, error) - // GetPendingTxns - // - // GetPendingTxns is called by the provider to get the pending transactions for the wallet. - GetPendingTxns(context.Context, *EmptyMessage) (*PendingTxnsResponse, error) - // CancelTransaction - // - // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. - CancelTransaction(context.Context, *CancelReq) (*CancelResponse, error) mustEmbedUnimplementedProviderServer() } @@ -239,12 +203,6 @@ func (UnimplementedProviderServer) GetStake(context.Context, *EmptyMessage) (*St func (UnimplementedProviderServer) GetMinStake(context.Context, *EmptyMessage) (*StakeResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMinStake not implemented") } -func (UnimplementedProviderServer) GetPendingTxns(context.Context, *EmptyMessage) (*PendingTxnsResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method GetPendingTxns not implemented") -} -func (UnimplementedProviderServer) CancelTransaction(context.Context, *CancelReq) (*CancelResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method CancelTransaction not implemented") -} func (UnimplementedProviderServer) mustEmbedUnimplementedProviderServer() {} // UnsafeProviderServer may be embedded to opt out of forward compatibility for this service. @@ -359,42 +317,6 @@ func _Provider_GetMinStake_Handler(srv interface{}, ctx context.Context, dec fun return interceptor(ctx, in, info, handler) } -func _Provider_GetPendingTxns_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(EmptyMessage) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ProviderServer).GetPendingTxns(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Provider_GetPendingTxns_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ProviderServer).GetPendingTxns(ctx, req.(*EmptyMessage)) - } - return interceptor(ctx, in, info, handler) -} - -func _Provider_CancelTransaction_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(CancelReq) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(ProviderServer).CancelTransaction(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: Provider_CancelTransaction_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(ProviderServer).CancelTransaction(ctx, req.(*CancelReq)) - } - return interceptor(ctx, in, info, handler) -} - // Provider_ServiceDesc is the grpc.ServiceDesc for Provider service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -414,14 +336,6 @@ var Provider_ServiceDesc = grpc.ServiceDesc{ MethodName: "GetMinStake", Handler: _Provider_GetMinStake_Handler, }, - { - MethodName: "GetPendingTxns", - Handler: _Provider_GetPendingTxns_Handler, - }, - { - MethodName: "CancelTransaction", - Handler: _Provider_CancelTransaction_Handler, - }, }, Streams: []grpc.StreamDesc{ { diff --git a/p2p/gen/openapi/debugapi/v1/debugapi.swagger.yaml b/p2p/gen/openapi/debugapi/v1/debugapi.swagger.yaml new file mode 100644 index 000000000..6273729b4 --- /dev/null +++ b/p2p/gen/openapi/debugapi/v1/debugapi.swagger.yaml @@ -0,0 +1,149 @@ +swagger: "2.0" +info: + title: Debug API + version: 1.0.0-alpha + license: + name: Business Source License 1.1 + url: https://github.com/primev/mev-commit/blob/main/LICENSE +consumes: + - application/json +produces: + - application/json +paths: + /v1/debug/cancel_transaction/{txHash}: + post: + summary: CancelTransaction + description: CancelTransaction is called by the provider to cancel a transaction sent from this wallet. + operationId: DebugService_CancelTransaction + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v1CancelTransactionResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + parameters: + - name: txHash + description: Hex string encoding of the hash of the transaction that the bidder wants to cancel. + in: path + required: true + type: string + /v1/debug/pending_transactions: + get: + summary: GetPendingTransactions + description: GetPendingTransactions is called by the provider to get the pending transactions for the wallet. + operationId: DebugService_GetPendingTransactions + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v1PendingTransactionsResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' + /v1/debug/topology: + get: + summary: GetTopology + description: |- + GetTopology is called by the user to get the topology of the node. The topology + includes connectivity information about the node. + operationId: DebugService_GetTopology + responses: + "200": + description: A successful response. + schema: + $ref: '#/definitions/v1TopologyResponse' + default: + description: An unexpected error response. + schema: + $ref: '#/definitions/googlerpcStatus' +definitions: + googlerpcStatus: + type: object + properties: + code: + type: integer + format: int32 + message: + type: string + details: + type: array + items: + type: object + $ref: '#/definitions/protobufAny' + protobufAny: + type: object + properties: + '@type': + type: string + additionalProperties: {} + protobufNullValue: + type: string + description: |- + `NullValue` is a singleton enumeration to represent the null value for the + `Value` type union. + + The JSON representation for `NullValue` is JSON `null`. + v1CancelTransactionResponse: + type: object + example: + txHash: 71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8 + properties: + txHash: + type: string + description: Hex string encoding of the hash of the transaction that the bidder wants to cancel. + pattern: '[a-fA-F0-9]{64}' + description: Hash of the cancellation transaction request. + title: Cancel response + required: + - txHash + v1PendingTransactionsResponse: + type: object + properties: + pendingTransactions: + type: array + items: + type: object + $ref: '#/definitions/v1TransactionInfo' + description: List of pending transactions in the provider provider_registry. + description: Transaction info returned by the provider. + title: Pending transactions list + required: + - pendingTransactions + v1TopologyResponse: + type: object + properties: + topology: + type: object + description: Topology of the node. + description: Topology of the node. + title: Topology + required: + - topology + v1TransactionInfo: + type: object + example: + created: 2009-11-10 23:00:00 +0000 UTC m=+0.000000001 + nonce: 1234 + txHash: 71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8 + properties: + txHash: + type: string + description: Hex string encoding of the hash of the transaction that the bidder wants to include in the block. + pattern: '[a-fA-F0-9]{64}' + nonce: + type: string + format: int64 + description: Nonce used for the transaction. + created: + type: string + description: Time when the transaction was created. + description: Transaction info returned by the provider. + title: Transaction info + required: + - txHash + - nonce + - created diff --git a/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml b/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml index df86240dd..479d5c6f6 100644 --- a/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml +++ b/p2p/gen/openapi/providerapi/v1/providerapi.swagger.yaml @@ -10,26 +10,6 @@ consumes: produces: - application/json paths: - /v1/provider/cancel_transaction/{txHash}: - post: - summary: CancelTransaction - description: CancelTransaction is called by the provider to cancel a transaction sent from this wallet. - operationId: Provider_CancelTransaction - responses: - "200": - description: A successful response. - schema: - $ref: '#/definitions/v1CancelResponse' - default: - description: An unexpected error response. - schema: - $ref: '#/definitions/googlerpcStatus' - parameters: - - name: txHash - description: Hex string encoding of the hash of the transaction that the bidder wants to cancel. - in: path - required: true - type: string /v1/provider/get_min_stake: get: summary: GetMinStake @@ -44,20 +24,6 @@ paths: description: An unexpected error response. schema: $ref: '#/definitions/googlerpcStatus' - /v1/provider/get_pending_txns: - get: - summary: GetPendingTxns - description: GetPendingTxns is called by the provider to get the pending transactions for the wallet. - operationId: Provider_GetPendingTxns - responses: - "200": - description: A successful response. - schema: - $ref: '#/definitions/v1PendingTxnsResponse' - default: - description: An unexpected error response. - schema: - $ref: '#/definitions/googlerpcStatus' /v1/provider/get_stake: get: summary: GetStake @@ -231,32 +197,6 @@ definitions: enum: - STATUS_ACCEPTED - STATUS_REJECTED - v1CancelResponse: - type: object - example: - txHash: 71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8 - properties: - txHash: - type: string - description: Hex string encoding of the hash of the transaction that the bidder wants to cancel. - pattern: '[a-fA-F0-9]{64}' - description: Hash of the cancellation transaction request. - title: Cancel response - required: - - txHash - v1PendingTxnsResponse: - type: object - properties: - pendingTxns: - type: array - items: - type: object - $ref: '#/definitions/v1TransactionInfo' - description: List of pending transactions in the provider provider_registry. - description: Transaction info returned by the provider. - title: Pending transactions list - required: - - pendingTxns v1StakeResponse: type: object example: @@ -266,27 +206,3 @@ definitions: type: string description: Get staked amount for provider in the provider provider_registry. title: Stake response - v1TransactionInfo: - type: object - example: - created: 2009-11-10 23:00:00 +0000 UTC m=+0.000000001 - nonce: 1234 - txHash: 71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8 - properties: - txHash: - type: string - description: Hex string encoding of the hash of the transaction that the bidder wants to include in the block. - pattern: '[a-fA-F0-9]{64}' - nonce: - type: string - format: int64 - description: Nonce used for the transaction. - created: - type: string - description: Time when the transaction was created. - description: Transaction info returned by the provider. - title: Transaction info - required: - - txHash - - nonce - - created diff --git a/p2p/integrationtest/real-bidder/main.go b/p2p/integrationtest/real-bidder/main.go index f60a50172..5724cdab0 100644 --- a/p2p/integrationtest/real-bidder/main.go +++ b/p2p/integrationtest/real-bidder/main.go @@ -188,7 +188,7 @@ func main() { } bundleLen := rand.Intn(10) - bundleStart := rand.Intn(len(currentBlock.txns)) + bundleStart := rand.Intn(len(currentBlock.txns) - 1) bundleEnd := bundleStart + bundleLen if bundleEnd > len(currentBlock.txns) { bundleEnd = len(currentBlock.txns) - 1 diff --git a/p2p/pkg/contracts/bidder_registry/bidder_registry.go b/p2p/pkg/contracts/bidder_registry/bidder_registry.go deleted file mode 100644 index 23d908b6c..000000000 --- a/p2p/pkg/contracts/bidder_registry/bidder_registry.go +++ /dev/null @@ -1,223 +0,0 @@ -package bidderregistrycontract - -import ( - "context" - "log/slog" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" - "github.com/primev/mev-commit/p2p/pkg/evmclient" -) - -var bidderRegistryABI = func() abi.ABI { - abi, err := abi.JSON(strings.NewReader(bidderregistry.BidderregistryMetaData.ABI)) - if err != nil { - panic(err) - } - return abi -} - -type Interface interface { - // DepositForSpecificWindow registers a bidder with the bidder_registry contract for a specific window. - DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error - // GetDeposit returns the stake of a bidder. - GetDeposit(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) - // GetMinDeposit returns the minimum stake required to register as a bidder. - GetMinDeposit(ctx context.Context) (*big.Int, error) - // CheckBidderRegistred returns true if bidder is registered - CheckBidderDeposit(ctx context.Context, address common.Address, window, blocksPerWindow *big.Int) bool - // WithdrawDeposit withdraws the stake of a bidder. - WithdrawDeposit(ctx context.Context, window *big.Int) (*big.Int, error) -} - -type bidderRegistryContract struct { - owner common.Address - bidderRegistryABI abi.ABI - bidderRegistryContractAddr common.Address - client evmclient.Interface - logger *slog.Logger -} - -func New( - owner common.Address, - bidderRegistryContractAddr common.Address, - client evmclient.Interface, - logger *slog.Logger, -) Interface { - return &bidderRegistryContract{ - owner: owner, - bidderRegistryABI: bidderRegistryABI(), - bidderRegistryContractAddr: bidderRegistryContractAddr, - client: client, - logger: logger, - } -} - -func (r *bidderRegistryContract) DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error { - callData, err := r.bidderRegistryABI.Pack("depositForSpecificWindow", window) - if err != nil { - r.logger.Error("error packing call data", "error", err) - return err - } - - txnHash, err := r.client.Send(ctx, &evmclient.TxRequest{ - To: &r.bidderRegistryContractAddr, - CallData: callData, - Value: amount, - }) - if err != nil { - return err - } - - receipt, err := r.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return err - } - - if receipt.Status != types.ReceiptStatusSuccessful { - r.logger.Error( - "deposit failed for bidder registry", - "txnHash", txnHash, - "receipt", receipt, - ) - return err - } - - return nil -} - -func (r *bidderRegistryContract) GetDeposit( - ctx context.Context, - address common.Address, - window *big.Int, -) (*big.Int, error) { - callData, err := r.bidderRegistryABI.Pack("getDeposit", address, window) - if err != nil { - r.logger.Error("error packing call data", "error", err) - return nil, err - } - - result, err := r.client.Call(ctx, &evmclient.TxRequest{ - To: &r.bidderRegistryContractAddr, - CallData: callData, - }) - if err != nil { - return nil, err - } - - results, err := r.bidderRegistryABI.Unpack("getDeposit", result) - if err != nil { - r.logger.Error("error unpacking result", "error", err) - return nil, err - } - - return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil -} - -func (r *bidderRegistryContract) GetMinDeposit(ctx context.Context) (*big.Int, error) { - callData, err := r.bidderRegistryABI.Pack("minDeposit") - if err != nil { - r.logger.Error("error packing call data", "error", err) - return nil, err - } - - result, err := r.client.Call(ctx, &evmclient.TxRequest{ - To: &r.bidderRegistryContractAddr, - CallData: callData, - }) - if err != nil { - return nil, err - } - - results, err := r.bidderRegistryABI.Unpack("minDeposit", result) - if err != nil { - r.logger.Error("error unpacking result", "error", err) - return nil, err - } - - return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil -} - -func (r *bidderRegistryContract) WithdrawDeposit(ctx context.Context, window *big.Int) (*big.Int, error) { - callData, err := r.bidderRegistryABI.Pack("withdrawBidderAmountFromWindow", r.owner, window) - if err != nil { - r.logger.Error("error packing call data", "error", err) - return nil, err - } - - txnHash, err := r.client.Send(ctx, &evmclient.TxRequest{ - To: &r.bidderRegistryContractAddr, - CallData: callData, - }) - if err != nil { - return nil, err - } - - receipt, err := r.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return nil, err - } - - if receipt.Status != types.ReceiptStatusSuccessful { - r.logger.Error( - "withdraw failed for bidder registry", - "txnHash", txnHash, - "receipt", receipt, - ) - return nil, err - } - - var bidderWithdrawn struct { - Bidder common.Address - Amount *big.Int - Window *big.Int - } - - for _, log := range receipt.Logs { - if len(log.Topics) > 1 { - bidderWithdrawn.Bidder = common.HexToAddress(log.Topics[1].Hex()) - } - - err := r.bidderRegistryABI.UnpackIntoInterface(&bidderWithdrawn, "BidderWithdrawn", log.Data) - if err != nil { - r.logger.Debug("Failed to unpack event", "err", err) - continue - } - r.logger.Info("bidder withdrawn", "address", bidderWithdrawn.Bidder, "withdrawn", bidderWithdrawn.Amount.Uint64(), "windowNumber", bidderWithdrawn.Window.Int64()) - } - - r.logger.Info("withdraw successful for bidder registry", "txnHash", txnHash, "bidder", bidderWithdrawn.Bidder) - - return bidderWithdrawn.Amount, nil -} - -func (r *bidderRegistryContract) CheckBidderDeposit( - ctx context.Context, - address common.Address, - window *big.Int, - blocksPerWindow *big.Int, -) bool { - minStake, err := r.GetMinDeposit(ctx) - if err != nil { - r.logger.Error("error getting min stake", "error", err) - return false - } - - stake, err := r.GetDeposit(ctx, address, window) - if err != nil { - r.logger.Error("error getting stake", "error", err) - return false - } - r.logger.Info("checking bidder deposit", - "stake", stake.Uint64(), - "blocksPerWindow", blocksPerWindow.Uint64(), - "minStake", minStake.Uint64(), - "window", window.Uint64(), - "address", address.Hex(), - ) - return (stake.Div(stake, blocksPerWindow)).Cmp(minStake) >= 0 -} diff --git a/p2p/pkg/contracts/bidder_registry/bidder_registry_test.go b/p2p/pkg/contracts/bidder_registry/bidder_registry_test.go deleted file mode 100644 index 2d736c0d4..000000000 --- a/p2p/pkg/contracts/bidder_registry/bidder_registry_test.go +++ /dev/null @@ -1,212 +0,0 @@ -package bidderregistrycontract_test - -import ( - "bytes" - "context" - "math/big" - "os" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - bidder_registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/bidder_registry" - "github.com/primev/mev-commit/p2p/pkg/evmclient" - mockevmclient "github.com/primev/mev-commit/p2p/pkg/evmclient/mock" - "github.com/primev/mev-commit/x/util" -) - -func TestBidderRegistryContract(t *testing.T) { - t.Parallel() - - owner := common.HexToAddress("abcd") - - t.Run("Deposit", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - txHash := common.HexToHash("abcdef") - amount := big.NewInt(1000000000000000000) - window := big.NewInt(1) - - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("depositForSpecificWindow", window) - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithSendFunc( - func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - if req.Value.Cmp(amount) != 0 { - t.Fatalf( - "expected amount to be %s, got %s", - amount.String(), req.Value.String(), - ) - } - - return txHash, nil - }, - ), - mockevmclient.WithWaitForReceiptFunc( - func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) { - if txnHash != txHash { - t.Fatalf( - "expected txn hash to be %s, got %s", - txHash.Hex(), txnHash.Hex(), - ) - } - return &types.Receipt{ - Status: 1, - }, nil - }, - ), - ) - - registryContract := bidder_registrycontract.New( - owner, - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - err = registryContract.DepositForSpecificWindow(context.Background(), amount, big.NewInt(1)) - if err != nil { - t.Fatal(err) - } - }) - - t.Run("GetDeposit", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) - address := common.HexToAddress("abcdef") - window := big.NewInt(1) - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("getDeposit", address, window) - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := bidder_registrycontract.New( - owner, - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - stakeAmt, err := registryContract.GetDeposit(context.Background(), address, window) - if err != nil { - t.Fatal(err) - } - - if stakeAmt.Cmp(amount) != 0 { - t.Fatalf("expected stake amount to be %s, got %s", amount.String(), stakeAmt.String()) - } - }) - - t.Run("GetMinimalStake", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) - - expCallData, err := bidder_registrycontract.BidderRegistryABI().Pack("minDeposit") - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := bidder_registrycontract.New( - owner, - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - stakeAmt, err := registryContract.GetMinDeposit(context.Background()) - if err != nil { - t.Fatal(err) - } - - if stakeAmt.Cmp(amount) != 0 { - t.Fatalf("expected stake amount to be %s, got %s", amount.String(), stakeAmt.String()) - } - }) - - t.Run("CheckBidderDeposit", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - blocksPerWindow := big.NewInt(64) - amount := new(big.Int).Mul(big.NewInt(1000000000000000000), blocksPerWindow) - address := common.HexToAddress("abcdef") - - callCount := 0 - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - callCount++ - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - - if callCount == 1 { - return new(big.Int).Div(amount, blocksPerWindow).FillBytes(make([]byte, 32)), nil - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := bidder_registrycontract.New( - owner, - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - window := big.NewInt(1) - isRegistered := registryContract.CheckBidderDeposit(context.Background(), address, window, blocksPerWindow) - if !isRegistered { - t.Fatal("expected bidder to be registered") - } - }) -} diff --git a/p2p/pkg/contracts/bidder_registry/export_test.go b/p2p/pkg/contracts/bidder_registry/export_test.go deleted file mode 100644 index db3ef7177..000000000 --- a/p2p/pkg/contracts/bidder_registry/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package bidderregistrycontract - -var BidderRegistryABI = bidderRegistryABI diff --git a/p2p/pkg/contracts/preconf/export_test.go b/p2p/pkg/contracts/preconf/export_test.go deleted file mode 100644 index 8a3554cb8..000000000 --- a/p2p/pkg/contracts/preconf/export_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package preconfcontract - -import "time" - -var PreConfABI = preconfABI - -func SetDefaultWaitTimeout(timeout time.Duration) func() { - oldTimeout := defaultWaitTimeout - defaultWaitTimeout = timeout - return func() { - defaultWaitTimeout = oldTimeout - } -} diff --git a/p2p/pkg/contracts/preconf/preconf.go b/p2p/pkg/contracts/preconf/preconf.go deleted file mode 100644 index 2fa043648..000000000 --- a/p2p/pkg/contracts/preconf/preconf.go +++ /dev/null @@ -1,145 +0,0 @@ -package preconfcontract - -import ( - "context" - "fmt" - "log/slog" - "math/big" - "strings" - "time" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - preconfcommitmentstore "github.com/primev/mev-commit/contracts-abi/clients/PreConfCommitmentStore" - "github.com/primev/mev-commit/p2p/pkg/evmclient" -) - -var preconfABI = func() abi.ABI { - abi, err := abi.JSON(strings.NewReader(preconfcommitmentstore.PreconfcommitmentstoreMetaData.ABI)) - if err != nil { - panic(err) - } - return abi -} - -var defaultWaitTimeout = 10 * time.Second - -type Interface interface { - StoreEncryptedCommitment( - ctx context.Context, - commitmentDigest []byte, - commitmentSignature []byte, - decayDispatchTimestamp uint64, - ) (common.Hash, error) - OpenCommitment( - ctx context.Context, - encryptedCommitmentIndex []byte, - bid string, - blockNumber int64, - txnHash string, - decayStartTimeStamp int64, - decayEndTimeStamp int64, - bidSignature []byte, - commitmentSignature []byte, - sharedSecretKey []byte, - ) (common.Hash, error) -} - -type preconfContract struct { - preconfABI abi.ABI - preconfContractAddr common.Address - client evmclient.Interface - logger *slog.Logger -} - -func New( - preconfContractAddr common.Address, - client evmclient.Interface, - logger *slog.Logger, -) Interface { - return &preconfContract{ - preconfABI: preconfABI(), - preconfContractAddr: preconfContractAddr, - client: client, - logger: logger, - } -} - -func (p *preconfContract) StoreEncryptedCommitment( - ctx context.Context, - commitmentDigest []byte, - commitmentSignature []byte, - decayDispatchTimestamp uint64, -) (common.Hash, error) { - callData, err := p.preconfABI.Pack( - "storeEncryptedCommitment", - [32]byte(commitmentDigest), - commitmentSignature, - decayDispatchTimestamp, - ) - if err != nil { - p.logger.Error("preconf contract storeEncryptedCommitment pack error", "err", err) - return common.Hash{}, err - } - - txnHash, err := p.client.Send(ctx, &evmclient.TxRequest{ - To: &p.preconfContractAddr, - CallData: callData, - }) - if err != nil { - return common.Hash{}, err - } - - return txnHash, nil -} - -func (p *preconfContract) OpenCommitment( - ctx context.Context, - encryptedCommitmentIndex []byte, - bid string, - blockNumber int64, - txnHash string, - decayStartTimeStamp int64, - decayEndTimeStamp int64, - bidSignature []byte, - commitmentSignature []byte, - sharedSecretKey []byte, -) (common.Hash, error) { - bidAmt, ok := new(big.Int).SetString(bid, 10) - if !ok { - p.logger.Error("Error converting bid to big.Int", "bid", bid) - return common.Hash{}, fmt.Errorf("error converting bid to big.Int, bid: %s", bid) - } - - var eciBytes [32]byte - copy(eciBytes[:], encryptedCommitmentIndex) - - callData, err := p.preconfABI.Pack( - "openCommitment", - eciBytes, - bidAmt.Uint64(), - uint64(blockNumber), - txnHash, - uint64(decayStartTimeStamp), - uint64(decayEndTimeStamp), - bidSignature, - commitmentSignature, - sharedSecretKey, - ) - if err != nil { - p.logger.Error("Error packing call data for openCommitment", "error", err) - return common.Hash{}, err - } - - txHash, err := p.client.Send(ctx, &evmclient.TxRequest{ - To: &p.preconfContractAddr, - CallData: callData, - }) - if err != nil { - return common.Hash{}, err - } - - p.logger.Info("preconf contract openCommitment successful", "txHash", txHash.String()) - - return txHash, nil -} diff --git a/p2p/pkg/contracts/preconf/preconf_test.go b/p2p/pkg/contracts/preconf/preconf_test.go deleted file mode 100644 index eb8129cf2..000000000 --- a/p2p/pkg/contracts/preconf/preconf_test.go +++ /dev/null @@ -1,83 +0,0 @@ -package preconfcontract_test - -import ( - "bytes" - "context" - "os" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - preconfcontract "github.com/primev/mev-commit/p2p/pkg/contracts/preconf" - "github.com/primev/mev-commit/p2p/pkg/evmclient" - mockevmclient "github.com/primev/mev-commit/p2p/pkg/evmclient/mock" - "github.com/primev/mev-commit/x/util" -) - -func TestPreconfContract(t *testing.T) { - t.Parallel() - - t.Run("StoreEncryptedCommitment", func(t *testing.T) { - preConfContract := common.HexToAddress("abcd") - txHash := common.HexToHash("abcdef") - commitment := [32]byte([]byte("abcdefabcdefabcdefabcdefabcdefaa")) - commitmentSignature := []byte("abcdef") - decayStart := uint64(1710095453035) - decayEnd := uint64(1710095454035) - dispatchTimestamp := decayStart + (decayEnd-decayStart)/2 - - expCallData, err := preconfcontract.PreConfABI().Pack( - "storeEncryptedCommitment", - commitment, - commitmentSignature, - dispatchTimestamp, - ) - - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithSendFunc( - func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) { - if req.To.Cmp(preConfContract) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - preConfContract.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - return txHash, nil - }, - ), - mockevmclient.WithWaitForReceiptFunc( - func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) { - if txnHash != txHash { - t.Fatalf("expected tx hash to be %s, got %s", txHash.Hex(), txnHash.Hex()) - } - return &types.Receipt{ - Status: 1, - }, nil - }, - ), - ) - - preConfContractClient := preconfcontract.New( - preConfContract, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - _, err = preConfContractClient.StoreEncryptedCommitment( - context.Background(), - commitment[:], - commitmentSignature, - dispatchTimestamp, - ) - if err != nil { - t.Fatal(err) - } - }) -} diff --git a/p2p/pkg/contracts/provider_registry/export_test.go b/p2p/pkg/contracts/provider_registry/export_test.go deleted file mode 100644 index e55d4275d..000000000 --- a/p2p/pkg/contracts/provider_registry/export_test.go +++ /dev/null @@ -1,3 +0,0 @@ -package registrycontract - -var RegistryABI = registryABI diff --git a/p2p/pkg/contracts/provider_registry/registry.go b/p2p/pkg/contracts/provider_registry/registry.go deleted file mode 100644 index edbfcd185..000000000 --- a/p2p/pkg/contracts/provider_registry/registry.go +++ /dev/null @@ -1,159 +0,0 @@ -package registrycontract - -import ( - "context" - "log/slog" - "math/big" - "strings" - - "github.com/ethereum/go-ethereum/accounts/abi" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" - "github.com/primev/mev-commit/p2p/pkg/evmclient" -) - -var registryABI = func() abi.ABI { - abi, err := abi.JSON(strings.NewReader(providerregistry.ProviderregistryMetaData.ABI)) - if err != nil { - panic(err) - } - return abi -} - -type Interface interface { - // RegisterProvider registers a provider with the provider_registry contract. - RegisterProvider(ctx context.Context, amount *big.Int) error - // GetStake returns the stake of a provider. - GetStake(ctx context.Context, address common.Address) (*big.Int, error) - // GetMinStake returns the minimum stake required to register as a provider. - GetMinStake(ctx context.Context) (*big.Int, error) - // CheckProviderRegistered returns true if provider is registered - CheckProviderRegistered(ctx context.Context, address common.Address) bool -} - -type registryContract struct { - registryABI abi.ABI - registryContractAddr common.Address - client evmclient.Interface - logger *slog.Logger -} - -func New( - registryContractAddr common.Address, - client evmclient.Interface, - logger *slog.Logger, -) Interface { - return ®istryContract{ - registryABI: registryABI(), - registryContractAddr: registryContractAddr, - client: client, - logger: logger, - } -} - -func (r *registryContract) RegisterProvider(ctx context.Context, amount *big.Int) error { - callData, err := r.registryABI.Pack("registerAndStake") - if err != nil { - r.logger.Error("error packing call data", "error", err) - return err - } - - txnHash, err := r.client.Send(ctx, &evmclient.TxRequest{ - To: &r.registryContractAddr, - CallData: callData, - Value: amount, - }) - if err != nil { - return err - } - - receipt, err := r.client.WaitForReceipt(ctx, txnHash) - if err != nil { - return err - } - - if receipt.Status != types.ReceiptStatusSuccessful { - r.logger.Error( - "provider_registry contract registerAndStake failed", - "txnHash", txnHash, - "receipt", receipt, - ) - return err - } - - r.logger.Info("provider_registry contract registerAndStake successful", "txnHash", txnHash) - - return nil -} - -func (r *registryContract) GetStake( - ctx context.Context, - address common.Address, -) (*big.Int, error) { - callData, err := r.registryABI.Pack("checkStake", address) - if err != nil { - r.logger.Error("error packing call data", "error", err) - return nil, err - } - - result, err := r.client.Call(ctx, &evmclient.TxRequest{ - To: &r.registryContractAddr, - CallData: callData, - }) - if err != nil { - return nil, err - } - - results, err := r.registryABI.Unpack("checkStake", result) - if err != nil { - r.logger.Error("error unpacking result", "error", err) - return nil, err - } - - return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil -} - -func (r *registryContract) GetMinStake(ctx context.Context) (*big.Int, error) { - callData, err := r.registryABI.Pack("minStake") - if err != nil { - r.logger.Error("error packing call data", "error", err) - return nil, err - } - - result, err := r.client.Call(ctx, &evmclient.TxRequest{ - To: &r.registryContractAddr, - CallData: callData, - }) - if err != nil { - return nil, err - } - - results, err := r.registryABI.Unpack("minStake", result) - if err != nil { - r.logger.Error("error unpacking result", "error", err) - return nil, err - } - - return abi.ConvertType(results[0], new(big.Int)).(*big.Int), nil -} - -func (r *registryContract) CheckProviderRegistered( - ctx context.Context, - address common.Address, -) bool { - - minStake, err := r.GetMinStake(ctx) - if err != nil { - r.logger.Error("error getting min stake", "error", err) - return false - } - - stake, err := r.GetStake(ctx, address) - if err != nil { - r.logger.Error("error getting stake", "error", err) - return false - } - - return stake.Cmp(minStake) >= 0 -} diff --git a/p2p/pkg/contracts/provider_registry/registry_test.go b/p2p/pkg/contracts/provider_registry/registry_test.go deleted file mode 100644 index 3770e0acb..000000000 --- a/p2p/pkg/contracts/provider_registry/registry_test.go +++ /dev/null @@ -1,198 +0,0 @@ -package registrycontract_test - -import ( - "bytes" - "context" - "math/big" - "os" - "testing" - - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/provider_registry" - "github.com/primev/mev-commit/p2p/pkg/evmclient" - mockevmclient "github.com/primev/mev-commit/p2p/pkg/evmclient/mock" - "github.com/primev/mev-commit/x/util" -) - -func TestRegistryContract(t *testing.T) { - t.Parallel() - - t.Run("RegisterProvider", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - txHash := common.HexToHash("abcdef") - amount := big.NewInt(1000000000000000000) - - expCallData, err := registrycontract.RegistryABI().Pack("registerAndStake") - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithSendFunc( - func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - if req.Value.Cmp(amount) != 0 { - t.Fatalf( - "expected amount to be %s, got %s", - amount.String(), req.Value.String(), - ) - } - - return txHash, nil - }, - ), - mockevmclient.WithWaitForReceiptFunc( - func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) { - if txnHash != txHash { - t.Fatalf( - "expected txn hash to be %s, got %s", - txHash.Hex(), txnHash.Hex(), - ) - } - return &types.Receipt{ - Status: 1, - }, nil - }, - ), - ) - - registryContract := registrycontract.New( - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - err = registryContract.RegisterProvider(context.Background(), amount) - if err != nil { - t.Fatal(err) - } - }) - - t.Run("GetStake", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) - address := common.HexToAddress("abcdef") - - expCallData, err := registrycontract.RegistryABI().Pack("checkStake", address) - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := registrycontract.New( - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - stakeAmt, err := registryContract.GetStake(context.Background(), address) - if err != nil { - t.Fatal(err) - } - - if stakeAmt.Cmp(amount) != 0 { - t.Fatalf("expected stake amount to be %s, got %s", amount.String(), stakeAmt.String()) - } - }) - - t.Run("GetMinimalStake", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) - - expCallData, err := registrycontract.RegistryABI().Pack("minStake") - if err != nil { - t.Fatal(err) - } - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - if !bytes.Equal(req.CallData, expCallData) { - t.Fatalf("expected call data to be %x, got %x", expCallData, req.CallData) - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := registrycontract.New( - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - stakeAmt, err := registryContract.GetMinStake(context.Background()) - if err != nil { - t.Fatal(err) - } - - if stakeAmt.Cmp(amount) != 0 { - t.Fatalf("expected stake amount to be %s, got %s", amount.String(), stakeAmt.String()) - } - }) - - t.Run("CheckProviderRegistered", func(t *testing.T) { - registryContractAddr := common.HexToAddress("abcd") - amount := big.NewInt(1000000000000000000) - address := common.HexToAddress("abcdef") - - mockClient := mockevmclient.New( - mockevmclient.WithCallFunc( - func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if req.To.Cmp(registryContractAddr) != 0 { - t.Fatalf( - "expected to address to be %s, got %s", - registryContractAddr.Hex(), req.To.Hex(), - ) - } - - return amount.FillBytes(make([]byte, 32)), nil - }, - ), - ) - - registryContract := registrycontract.New( - registryContractAddr, - mockClient, - util.NewTestLogger(os.Stdout), - ) - - isRegistered := registryContract.CheckProviderRegistered(context.Background(), address) - if !isRegistered { - t.Fatalf("expected bidder to be registered") - } - }) -} diff --git a/p2p/pkg/debugapi/debugapi.go b/p2p/pkg/debugapi/debugapi.go deleted file mode 100644 index 057f9e590..000000000 --- a/p2p/pkg/debugapi/debugapi.go +++ /dev/null @@ -1,83 +0,0 @@ -package debugapi - -import ( - "log/slog" - "net/http" - - "github.com/ethereum/go-ethereum/common" - "github.com/primev/mev-commit/p2p/pkg/apiserver" - "github.com/primev/mev-commit/p2p/pkg/p2p" - "github.com/primev/mev-commit/p2p/pkg/p2p/libp2p" - "github.com/primev/mev-commit/p2p/pkg/topology" -) - -type APIServer interface { - ChainHandlers(string, http.Handler, ...func(http.Handler) http.Handler) -} - -type Topology interface { - GetPeers(topology.Query) []p2p.Peer -} - -func RegisterAPI( - srv APIServer, - topo Topology, - p2pSvc *libp2p.Service, - logger *slog.Logger, -) { - d := &debugapi{ - topo: topo, - p2p: p2pSvc, - logger: logger, - } - - srv.ChainHandlers( - "/topology", - apiserver.MethodHandler("GET", d.handleTopology), - ) -} - -type debugapi struct { - topo Topology - p2p *libp2p.Service - logger *slog.Logger -} - -type topologyResponse struct { - Self map[string]interface{} `json:"self"` - ConnectedPeers map[string][]common.Address `json:"connected_peers"` - BlockedPeers []p2p.BlockedPeerInfo `json:"blocked_peers"` -} - -func (d *debugapi) handleTopology(w http.ResponseWriter, r *http.Request) { - logger := d.logger.With("method", "handleTopology") - providers := d.topo.GetPeers(topology.Query{Type: p2p.PeerTypeProvider}) - bidders := d.topo.GetPeers(topology.Query{Type: p2p.PeerTypeBidder}) - - topoResp := topologyResponse{ - Self: d.p2p.Self(), - ConnectedPeers: make(map[string][]common.Address), - } - - if len(providers) > 0 { - connectedProviders := make([]common.Address, len(providers)) - for idx, provider := range providers { - connectedProviders[idx] = provider.EthAddress - } - topoResp.ConnectedPeers["providers"] = connectedProviders - } - if len(bidders) > 0 { - connectedBidders := make([]common.Address, len(bidders)) - for idx, bidder := range bidders { - connectedBidders[idx] = bidder.EthAddress - } - topoResp.ConnectedPeers["bidders"] = connectedBidders - } - - topoResp.BlockedPeers = d.p2p.BlockedPeers() - - err := apiserver.WriteResponse(w, http.StatusOK, topoResp) - if err != nil { - logger.Error("error writing response", "err", err) - } -} diff --git a/p2p/pkg/evmclient/evm.go b/p2p/pkg/evmclient/evm.go deleted file mode 100644 index 6efcfa522..000000000 --- a/p2p/pkg/evmclient/evm.go +++ /dev/null @@ -1,146 +0,0 @@ -package evmclient - -import ( - "context" - "math/big" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/ethclient" - "github.com/ethereum/go-ethereum/rpc" -) - -// StructLog represents a single operation (op code) executed during -// a transaction. It is part of the execution trace and provides detailed -// information about each step of the transaction execution. -type StructLog struct { - // Pc indicates the program counter at the point of execution. - Pc uint64 `json:"pc,omitempty"` - // Op is the name of the opcode that was executed. - Op string `json:"op,omitempty"` - // Gas represents the gas available at this step of execution. - Gas uint64 `json:"gas,omitempty"` - // GasCost is the amount of gas used by this operation. - GasCost uint64 `json:"gasCost,omitempty"` - // Depth indicates the call depth of the current operation. - Depth int `json:"depth,omitempty"` - // Error reports any exceptions or errors encountered during the - // execution of the corresponding operation (op code) in the EVM. - Error string `json:"error,omitempty"` - // Stack is the state of the EVM stack at this point of execution. - Stack []string `json:"stack,omitempty"` - // Memory represents the contents of the EVM memory at this point. - Memory []string `json:"memory,omitempty"` - // Storage is a map representing the contract storage state after this - // operation. The keys are storage slots and the values are the data - // stored at those slots. - Storage map[string]string `json:"storage,omitempty"` -} - -// TransactionTrace encapsulates the result of tracing an Ethereum transaction, -// providing a high-level overview of the transaction's execution and its -// effects on the EVM state. -type TransactionTrace struct { - // Failed indicates whether the transaction was successful. - Failed bool `json:"failed,omitempty"` - // Gas indicates the total gas used by the transaction. - Gas uint64 `json:"gas,omitempty"` - // ReturnValue is the data returned by the transaction if it was a call - // to a contract. - ReturnValue string `json:"returnValue,omitempty"` - // StructLogs is a slice of StructLog entries, each representing a step - // in the transaction's execution. These logs provide a detailed trace - // of the EVM operations, allowing for deep inspection of transaction - // behavior. - StructLogs []StructLog `json:"structLogs,omitempty"` -} - -// Debugger defines an interface for EVM debugging tools. -type Debugger interface { - // TraceTransaction takes a transaction hash and returns - // a detailed trace of the transaction's execution. - TraceTransaction(ctx context.Context, txHash common.Hash) (*TransactionTrace, error) -} - -// EVM is an interface for interacting with the Ethereum Virtual Machine. It includes -// subset of the methods from the go-ethereum ethclient.Client interface. -type EVM interface { - // Client returns the underlying RPC client. - Batcher() Batcher - // NetworkID returns the network ID associated with this client. - NetworkID(ctx context.Context) (*big.Int, error) - // BlockNumber returns the most recent block number - BlockNumber(ctx context.Context) (uint64, error) - // BlockByNumber returns the block identified by number. - BlockByNumber(ctx context.Context, number *big.Int) (*types.Block, error) - // PendingNonceAt retrieves the current pending nonce associated with an account. - PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) - // NonceAt retrieves the current nonce associated with an account. - NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) - // SuggestGasPrice retrieves the currently suggested gas price to allow a timely - // execution of a transaction. - // Note after eip 1559 this returns suggested priority fee per gas + suggested base fee per gas. - SuggestGasPrice(ctx context.Context) (*big.Int, error) - // SuggestGasTipCap retrieves the currently suggested 1559 priority fee to allow - // a timely execution of a transaction. - SuggestGasTipCap(ctx context.Context) (*big.Int, error) - // EstimateGas tries to estimate the gas needed to execute a specific - // transaction based on the current pending state of the backend blockchain. - // There is no guarantee that this is the true gas limit requirement as other - // transactions may be added or removed by miners, but it should provide a basis - // for setting a reasonable default. - EstimateGas(ctx context.Context, call ethereum.CallMsg) (gas uint64, err error) - // SendTransaction injects the transaction into the pending pool for execution. - SendTransaction(ctx context.Context, tx *types.Transaction) error - // CallContract executes an Ethereum contract call with the specified data as the - // input. - CallContract(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) - // TransactionReceipt returns the receipt of a transaction by transaction hash. - TransactionReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - // TransactionByHash checks the pool of pending transactions in addition to the - // blockchain. The isPending return value indicates whether the transaction has been - // mined yet. Note that the transaction may not be part of the canonical chain even if - // it's not pending. - TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, isPending bool, err error) - // SubscribeFilterLogs creates a new subscription to filter logs. It returns a subscription - SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) - // FilterLogs executes a filter query to return the logs that satisfy the specified - FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) -} - -type Batcher interface { - // BatchCallContext executes multiple Ethereum contract calls concurrently with the - // specified data as the input. - BatchCallContext(ctx context.Context, b []rpc.BatchElem) error -} - -type evm struct { - *ethclient.Client -} - -func (e *evm) Batcher() Batcher { - return e.Client.Client() -} - -// TraceTransaction implements Debugger.TraceTransaction interface. -func (e *evm) TraceTransaction(ctx context.Context, txHash common.Hash) (*TransactionTrace, error) { - result := new(TransactionTrace) - traceOptions := map[string]interface{}{} // Empty map for default options. - if err := e.Client.Client().CallContext( - ctx, - result, - "debug_traceTransaction", - txHash, - traceOptions, - ); err != nil { - return nil, err - } - return result, nil -} - -func WrapEthClient(client *ethclient.Client) EVM { - return &evm{ - Client: client, - } -} diff --git a/p2p/pkg/evmclient/evmclient.go b/p2p/pkg/evmclient/evmclient.go deleted file mode 100644 index aad5558bf..000000000 --- a/p2p/pkg/evmclient/evmclient.go +++ /dev/null @@ -1,434 +0,0 @@ -package evmclient - -import ( - "context" - "errors" - "fmt" - "log/slog" - "math/big" - "sort" - "sync" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/primev/mev-commit/x/keysigner" - "github.com/prometheus/client_golang/prometheus" -) - -type TxRequest struct { - To *common.Address - CallData []byte - GasPrice *big.Int - GasLimit uint64 - GasFeeCap *big.Int - Value *big.Int -} - -func (t TxRequest) String() string { - return fmt.Sprintf( - "To: %s, CallData: %x, GasPrice: %d, GasLimit: %d, GasFeeCap: %d, Value: %d", - t.To.String(), - t.CallData, - t.GasPrice, - t.GasLimit, - t.GasFeeCap, - t.Value, - ) -} - -type Interface interface { - Send(ctx context.Context, tx *TxRequest) (common.Hash, error) - WaitForReceipt(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - Call(ctx context.Context, tx *TxRequest) ([]byte, error) - CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) - SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) - BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) - BlockNumber(ctx context.Context) (uint64, error) - FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) -} - -type EvmClient struct { - mtx sync.Mutex - chainID *big.Int - ethClient EVM - owner common.Address - keySigner keysigner.KeySigner - logger *slog.Logger - nonce uint64 - metrics *metrics - sentTxs map[common.Hash]txnDetails - monitor *txmonitor -} - -type txnDetails struct { - nonce uint64 - created time.Time -} - -func New( - keySigner keysigner.KeySigner, - ethClient EVM, - logger *slog.Logger, -) (*EvmClient, error) { - chainID, err := ethClient.NetworkID(context.Background()) - if err != nil { - return nil, fmt.Errorf("failed to get chain id: %w", err) - } - - m := newMetrics() - address := keySigner.GetAddress() - monitor := newTxMonitor( - address, - ethClient, - logger.With("component", "evmclient/txmonitor"), - m, - ) - - return &EvmClient{ - chainID: chainID, - ethClient: ethClient, - owner: address, - keySigner: keySigner, - logger: logger, - metrics: m, - sentTxs: make(map[common.Hash]txnDetails), - monitor: monitor, - }, nil -} - -func (c *EvmClient) Close() error { - return c.monitor.Close() -} - -func (c *EvmClient) suggestMaxFeeAndTipCap( - ctx context.Context, - gasPrice *big.Int, -) (*big.Int, *big.Int, error) { - // Returns priority fee per gas - gasTipCap, err := c.ethClient.SuggestGasTipCap(ctx) - if err != nil { - return nil, nil, fmt.Errorf("failed to suggest gas tip cap: %w", err) - } - - // Returns priority fee per gas + base fee per gas - if gasPrice == nil { - gasPrice, err = c.ethClient.SuggestGasPrice(ctx) - if err != nil { - return nil, nil, fmt.Errorf("failed to suggest gas price: %w", err) - } - } - - return gasPrice, gasTipCap, nil -} - -func (c *EvmClient) newTx(ctx context.Context, req *TxRequest, nonce uint64) (*types.Transaction, error) { - var err error - - if req.GasLimit == 0 { - // if gas limit is not provided, estimate it - req.GasLimit, err = c.ethClient.EstimateGas(ctx, ethereum.CallMsg{ - From: c.owner, - To: req.To, - Data: req.CallData, - Value: req.Value, - }) - if err != nil { - return nil, fmt.Errorf("failed to estimate gas: %w", err) - } - } - - gasFeeCap, gasTipCap, err := c.suggestMaxFeeAndTipCap(ctx, req.GasPrice) - if err != nil { - return nil, fmt.Errorf("failed to suggest max fee and tip cap: %w", err) - } - - return types.NewTx(&types.DynamicFeeTx{ - Nonce: nonce, - ChainID: c.chainID, - To: req.To, - Value: req.Value, - Gas: req.GasLimit, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Data: req.CallData, - }), nil -} - -func (c *EvmClient) getNonce(ctx context.Context) (uint64, error) { - accountNonce, err := c.ethClient.PendingNonceAt(ctx, c.owner) - if err != nil { - return 0, fmt.Errorf("failed to get nonce: %w", err) - } - - // first nonce - if accountNonce == 0 { - return 0, nil - } - - if c.nonce == 0 { - c.nonce = accountNonce - } - - // if external transactions were sent from the owner account, update the - // nonce to the latest one - if accountNonce > c.nonce { - c.nonce = accountNonce - } - - c.metrics.LastUsedNonce.Set(float64(c.nonce)) - - return c.nonce, nil -} - -func (c *EvmClient) Send(ctx context.Context, tx *TxRequest) (common.Hash, error) { - c.mtx.Lock() - defer c.mtx.Unlock() - - c.metrics.AttemptedTxCount.Inc() - - nonce, err := c.getNonce(ctx) - if err != nil { - return common.Hash{}, fmt.Errorf("failed to get nonce: %w", err) - } - - if !c.monitor.allowNonce(nonce) { - return common.Hash{}, fmt.Errorf("too many pending transactions") - } - - txnData, err := c.newTx(ctx, tx, nonce) - if err != nil { - c.logger.Error("failed to create tx", "err", err) - return common.Hash{}, err - } - - signedTx, err := c.keySigner.SignTx(txnData, c.chainID) - if err != nil { - c.logger.Error("failed to sign tx", "err", err) - return common.Hash{}, fmt.Errorf("failed to sign tx: %w", err) - } - - err = c.ethClient.SendTransaction(ctx, signedTx) - if err != nil { - c.logger.Error("failed to send tx", "err", err) - return common.Hash{}, err - } - - c.metrics.SentTxCount.Inc() - c.nonce++ - c.logger.Info("sent txn", "tx", txnString(txnData), "txHash", signedTx.Hash().Hex()) - - c.sentTxs[signedTx.Hash()] = txnDetails{nonce: nonce, created: time.Now()} - c.waitForTxn(signedTx.Hash(), nonce) - - return signedTx.Hash(), nil -} - -func (c *EvmClient) waitForTxn(txnHash common.Hash, nonce uint64) { - go func() { - res, err := c.monitor.watchTx(txnHash, nonce) - if err != nil { - c.logger.Error("failed to watch tx", "err", err) - return - } - - receipt := <-res - if receipt.Err != nil { - c.logger.Warn("failed to get receipt", "err", receipt.Err) - if !errors.Is(err, ErrTxnCancelled) { - return - } - } else { - switch receipt.Receipt.Status { - case types.ReceiptStatusSuccessful: - c.metrics.SuccessfulTxCount.Inc() - case types.ReceiptStatusFailed: - c.metrics.FailedTxCount.Inc() - } - } - c.mtx.Lock() - delete(c.sentTxs, txnHash) - c.mtx.Unlock() - - c.logger.Info("tx status", "txHash", txnHash.Hex(), "status", receipt.Receipt.Status) - }() - -} - -func txnString(tx *types.Transaction) string { - return fmt.Sprintf( - "nonce=%d, gasPrice=%s, gasLimit=%d, gasTip=%s gasFeeCap=%s to=%s, value=%s, data=%x", - tx.Nonce(), - tx.GasPrice().String(), - tx.Gas(), - tx.GasTipCap().String(), - tx.GasFeeCap().String(), - tx.To().Hex(), - tx.Value().String(), - tx.Data(), - ) -} - -func (c *EvmClient) WaitForReceipt( - ctx context.Context, - txHash common.Hash, -) (*types.Receipt, error) { - - c.mtx.Lock() - d, ok := c.sentTxs[txHash] - c.mtx.Unlock() - if !ok { - return nil, fmt.Errorf("tx not found") - } - - res, err := c.monitor.watchTx(txHash, d.nonce) - if err != nil { - return nil, fmt.Errorf("failed to watch tx: %w", err) - } - - select { - case receipt := <-res: - if receipt.Err != nil { - return nil, fmt.Errorf("failed to get receipt: %w", receipt.Err) - } - return receipt.Receipt, nil - case <-ctx.Done(): - return nil, ctx.Err() - } -} - -func (c *EvmClient) Call( - ctx context.Context, - tx *TxRequest, -) ([]byte, error) { - - msg := ethereum.CallMsg{ - From: c.owner, - To: tx.To, - Data: tx.CallData, - Gas: tx.GasLimit, - GasPrice: tx.GasPrice, - Value: tx.Value, - } - - result, err := c.ethClient.CallContract(ctx, msg, nil) - if err != nil { - c.logger.Error("failed to call contract", "err", err) - return nil, fmt.Errorf("failed to call contract: %w", err) - } - - return result, nil -} - -func (c *EvmClient) CancelTx(ctx context.Context, txnHash common.Hash) (common.Hash, error) { - c.mtx.Lock() - defer c.mtx.Unlock() - - txn, isPending, err := c.ethClient.TransactionByHash(ctx, txnHash) - if err != nil { - if errors.Is(err, ethereum.NotFound) { - c.metrics.NotFoundDuringCancelCount.Inc() - } - return common.Hash{}, fmt.Errorf("failed to get transaction: %w", err) - } - - if !isPending { - c.metrics.NotFoundDuringCancelCount.Inc() - return common.Hash{}, ethereum.NotFound - } - - gasFeeCap, gasTipCap, err := c.suggestMaxFeeAndTipCap(ctx, txn.GasPrice()) - if err != nil { - return common.Hash{}, fmt.Errorf("failed to suggest max fee and tip cap: %w", err) - } - - if gasFeeCap.Cmp(txn.GasFeeCap()) <= 0 { - gasFeeCap = txn.GasFeeCap() - } - - if gasTipCap.Cmp(txn.GasTipCap()) <= 0 { - gasTipCap = txn.GasTipCap() - } - - // increase gas fee cap and tip cap by 10% for better chance of replacing - gasTipCap = new(big.Int).Div(new(big.Int).Mul(gasTipCap, big.NewInt(110)), big.NewInt(100)) - gasFeeCap.Add(gasFeeCap, gasTipCap) - - tx := types.NewTx(&types.DynamicFeeTx{ - Nonce: txn.Nonce(), - ChainID: c.chainID, - To: &c.owner, - Value: big.NewInt(0), - Gas: 21000, - GasFeeCap: gasFeeCap, - GasTipCap: gasTipCap, - Data: []byte{}, - }) - - signedTx, err := c.keySigner.SignTx(tx, c.chainID) - if err != nil { - c.logger.Error("failed to sign cancel tx", "err", err) - return common.Hash{}, fmt.Errorf("failed to sign cancel tx: %w", err) - } - - err = c.ethClient.SendTransaction(ctx, signedTx) - if err != nil { - c.logger.Error("failed to send cancel tx", "err", err) - return common.Hash{}, err - } - - c.metrics.CancelledTxCount.Inc() - c.logger.Info("sent cancel txn", "txHash", signedTx.Hash().Hex()) - - c.sentTxs[signedTx.Hash()] = txnDetails{nonce: txn.Nonce(), created: time.Now()} - c.waitForTxn(signedTx.Hash(), txn.Nonce()) - - return signedTx.Hash(), nil -} - -func (c *EvmClient) SubscribeFilterLogs(ctx context.Context, query ethereum.FilterQuery, logsCh chan<- types.Log) (ethereum.Subscription, error) { - return c.ethClient.SubscribeFilterLogs(ctx, query, logsCh) -} - -func (c *EvmClient) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) { - return c.ethClient.BlockByNumber(ctx, blockNumber) -} - -func (c *EvmClient) BlockNumber(ctx context.Context) (uint64, error) { - return c.ethClient.BlockNumber(ctx) -} - -func (c *EvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - return c.ethClient.FilterLogs(ctx, query) -} - -type TxnInfo struct { - Hash string - Nonce uint64 - Created string -} - -func (c *EvmClient) PendingTxns() []TxnInfo { - c.mtx.Lock() - defer c.mtx.Unlock() - - var txns []TxnInfo - for hash, d := range c.sentTxs { - txns = append(txns, TxnInfo{ - Hash: hash.Hex(), - Nonce: d.nonce, - Created: d.created.String(), - }) - } - - sort.Slice(txns, func(i, j int) bool { - return txns[i].Nonce < txns[j].Nonce - }) - - return txns -} - -func (c *EvmClient) Metrics() []prometheus.Collector { - return c.metrics.collectors() -} diff --git a/p2p/pkg/evmclient/evmclient_test.go b/p2p/pkg/evmclient/evmclient_test.go deleted file mode 100644 index 48bce46c1..000000000 --- a/p2p/pkg/evmclient/evmclient_test.go +++ /dev/null @@ -1,354 +0,0 @@ -package evmclient_test - -import ( - "bytes" - "context" - "errors" - "fmt" - "math/big" - "os" - "testing" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" - "github.com/ethereum/go-ethereum/rpc" - "github.com/primev/mev-commit/p2p/pkg/evmclient" - "github.com/primev/mev-commit/p2p/pkg/evmclient/mockevm" - mockkeysigner "github.com/primev/mev-commit/x/keysigner/mock" - "github.com/primev/mev-commit/x/util" -) - -func TestSendCall(t *testing.T) { - t.Parallel() - - owner := common.HexToAddress("0xab") - callData := []byte("call data") - nonce := uint64(1) - chainID := big.NewInt(1) - unblockMonitor := make(chan struct{}) - - pk, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - ks := mockkeysigner.NewMockKeySigner(pk, owner) - - evm := mockevm.NewMockEvm( - chainID.Uint64(), - mockevm.WithPendingNonceAtFunc( - func(ctx context.Context, account common.Address) (uint64, error) { - if account != owner { - t.Errorf("expected owner to be %v, got %v", owner, account) - } - return nonce, nil - }, - ), - mockevm.WithEstimateGasFunc( - func(ctx context.Context, call ethereum.CallMsg) (uint64, error) { - if call.From != owner { - return 0, fmt.Errorf("expected from to be %v, got %v", owner, call.From) - } - if call.To.Hex() != owner.Hex() { - return 0, fmt.Errorf("expected to to be %v, got %v", owner, call.To) - } - if string(call.Data) != string(callData) { - return 0, fmt.Errorf("expected call data to be %v, got %v", callData, call.Data) - } - return 21000, nil - }, - ), - mockevm.WithSuggestGasPriceFunc( - func(ctx context.Context) (*big.Int, error) { - return big.NewInt(2000000000), nil - }, - ), - mockevm.WithSuggestGasTipCapFunc( - func(ctx context.Context) (*big.Int, error) { - return big.NewInt(1000000000), nil - }, - ), - mockevm.WithSendTransactionFunc( - func(ctx context.Context, tx *types.Transaction) error { - if tx.GasFeeCap().Cmp(big.NewInt(2000000000)) != 0 { - return fmt.Errorf("expected gas price to be 2000000000, got %v", tx.GasPrice()) - } - if tx.GasTipCap().Cmp(big.NewInt(1000000000)) != 0 { - return fmt.Errorf("expected gas tip cap to be 1000000000, got %v", tx.GasTipCap()) - } - if tx.Gas() != 21000 { - return fmt.Errorf("expected gas to be 21000, got %v", tx.Gas()) - } - return nil - }, - ), - mockevm.WithBlockNumFunc( - func(ctx context.Context) (uint64, error) { - select { - case <-unblockMonitor: - return 1, nil - case <-ctx.Done(): - return 0, ctx.Err() - } - }, - ), - mockevm.WithNonceAtFunc( - func(ctx context.Context, account common.Address, blockNum *big.Int) (uint64, error) { - if account != owner { - return 0, fmt.Errorf("expected owner to be %v, got %v", owner, account) - } - if blockNum.Uint64() != 1 { - return 0, fmt.Errorf("expected blockNum to be 1, got %v", blockNum) - } - return nonce + 1, nil - }, - ), - mockevm.WithBatcherFunc( - func(ctx context.Context, elems []rpc.BatchElem) error { - if len(elems) != 1 { - return fmt.Errorf("expected 1 batch elem, got %v", len(elems)) - } - if elems[0].Method != "eth_getTransactionReceipt" { - return fmt.Errorf( - "expected method to be eth_getTransactionReceipt, got %v", - elems[0].Method, - ) - } - if len(elems[0].Args) != 1 { - return fmt.Errorf("expected 1 arg, got %v", len(elems[0].Args)) - } - elems[0].Result.(*types.Receipt).Status = 1 - return nil - }, - ), - mockevm.WithCallContractFunc( - func(ctx context.Context, call ethereum.CallMsg, blockNum *big.Int) ([]byte, error) { - if call.From != owner { - return nil, fmt.Errorf("expected from to be %v, got %v", owner, call.From) - } - if call.To.Hex() != owner.Hex() { - return nil, fmt.Errorf("expected to to be %v, got %v", owner, call.To) - } - if string(call.Data) != string(callData) { - return nil, fmt.Errorf("expected call data to be %v, got %v", callData, call.Data) - } - return []byte("result"), nil - }, - ), - ) - - client, err := evmclient.New(ks, evm, util.NewTestLogger(os.Stdout)) - if err != nil { - t.Fatal(err) - } - - txHash, err := client.Send(context.Background(), &evmclient.TxRequest{ - To: &owner, - CallData: callData, - Value: big.NewInt(0), - }) - if err != nil { - t.Fatal(err) - } - - txns := client.PendingTxns() - if len(txns) != 1 { - t.Fatalf("expected 1 pending txn, got %v", len(txns)) - } - - if txns[0].Hash != txHash.Hex() { - t.Errorf("expected hash to be %v, got %v", txHash, txns[0].Hash) - } - - if txns[0].Nonce != nonce { - t.Errorf("expected nonce to be %v, got %v", nonce, txns[0].Nonce) - } - - close(unblockMonitor) - - start := time.Now() - for { - if len(client.PendingTxns()) == 0 { - break - } - if time.Since(start) > 5*time.Second { - t.Fatal("timed out waiting for pending txns to be removed") - } - time.Sleep(100 * time.Millisecond) - } - - resp, err := client.Call(context.Background(), &evmclient.TxRequest{ - To: &owner, - CallData: callData, - }) - if err != nil { - t.Fatal(err) - } - - if string(resp) != "result" { - t.Errorf("expected result to be %v, got %v", "result", string(resp)) - } - - err = client.Close() - if err != nil { - t.Fatal(err) - } -} - -func TestCancel(t *testing.T) { - t.Parallel() - - owner := common.HexToAddress("0xab") - callData := []byte("call data") - nonce := uint64(1) - chainID := big.NewInt(1) - unblockMonitor := make(chan struct{}) - successHash := common.HexToHash("0x123") - blkNum := uint64(1) - - pk, err := crypto.GenerateKey() - if err != nil { - t.Fatal(err) - } - - ks := mockkeysigner.NewMockKeySigner(pk, owner) - - evm := mockevm.NewMockEvm( - chainID.Uint64(), - mockevm.WithPendingNonceAtFunc( - func(ctx context.Context, account common.Address) (uint64, error) { - return nonce, nil - }, - ), - mockevm.WithSuggestGasTipCapFunc( - func(ctx context.Context) (*big.Int, error) { - return big.NewInt(1000000000), nil - }, - ), - mockevm.WithSendTransactionFunc( - func(ctx context.Context, tx *types.Transaction) error { - if bytes.Equal(tx.Data(), callData) { - return nil - } - if tx.GasFeeCap().Cmp(big.NewInt(2000000000)) <= 0 { - return fmt.Errorf("expected gas price to be 2000000000, got %v", tx.GasFeeCap()) - } - if tx.GasTipCap().Cmp(big.NewInt(1000000000)) <= 0 { - return fmt.Errorf("expected gas tip cap to be 1000000000, got %v", tx.GasTipCap()) - } - return nil - }, - ), - mockevm.WithBlockNumFunc( - func(ctx context.Context) (uint64, error) { - select { - case <-unblockMonitor: - defer func() { blkNum++ }() - return blkNum, nil - case <-ctx.Done(): - return 0, ctx.Err() - } - }, - ), - mockevm.WithNonceAtFunc( - func(ctx context.Context, account common.Address, blockNum *big.Int) (uint64, error) { - return nonce + 1, nil - }, - ), - mockevm.WithBatcherFunc( - func(ctx context.Context, elems []rpc.BatchElem) error { - for i, elem := range elems { - if elem.Args[0].(common.Hash) != successHash { - elems[i].Error = ethereum.NotFound - } else { - elems[i].Result.(*types.Receipt).Status = 1 - } - } - return nil - }, - ), - mockevm.WithTransactionByHashFunc( - func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) { - return types.NewTx(&types.DynamicFeeTx{ - ChainID: chainID, - Nonce: nonce, - Data: callData, - GasFeeCap: big.NewInt(2000000000), - GasTipCap: big.NewInt(1000000000), - Gas: 21000, - Value: big.NewInt(0), - }), true, nil - }, - ), - ) - - client, err := evmclient.New(ks, evm, util.NewTestLogger(os.Stdout)) - if err != nil { - t.Fatal(err) - } - - ctx := context.Background() - - txHash, err := client.Send(ctx, &evmclient.TxRequest{ - To: &owner, - CallData: callData, - GasLimit: 21000, - GasPrice: big.NewInt(1000000000), - Value: big.NewInt(0), - }) - if err != nil { - t.Fatal(err) - } - - errC := make(chan error, 1) - go func() { - _, err := client.WaitForReceipt(ctx, txHash) - if err != nil { - errC <- err - return - } - errC <- nil - }() - - cancelHash, err := client.CancelTx(ctx, txHash) - if err != nil { - t.Fatal(err) - } - - successHash = cancelHash - - txns := client.PendingTxns() - if len(txns) != 2 { - t.Fatalf("expected 1 pending txn, got %v", len(txns)) - } - for _, txn := range txns { - if txn.Hash != txHash.Hex() && txn.Hash != cancelHash.Hex() { - t.Errorf("expected hash to be %v or %v, got %v", txHash, cancelHash, txn.Hash) - } - if txn.Nonce != nonce { - t.Errorf("expected nonce to be %v, got %v", nonce, txn.Nonce) - } - } - - close(unblockMonitor) - - res, err := client.WaitForReceipt(ctx, cancelHash) - if err != nil { - t.Fatal(err) - } - if res.Status != 1 { - t.Errorf("expected status to be 1, got %v", res.Status) - } - - select { - case err := <-errC: - if !errors.Is(err, evmclient.ErrTxnCancelled) { - t.Fatalf("expected error to be %v, got %v", evmclient.ErrTxnCancelled, err) - } - case <-time.After(5 * time.Second): - t.Fatal("timed out waiting for receipt") - } -} diff --git a/p2p/pkg/evmclient/metrics.go b/p2p/pkg/evmclient/metrics.go deleted file mode 100644 index e964884c5..000000000 --- a/p2p/pkg/evmclient/metrics.go +++ /dev/null @@ -1,93 +0,0 @@ -package evmclient - -import "github.com/prometheus/client_golang/prometheus" - -const ( - defaultMetricsNamespace = "mev_commit" -) - -type metrics struct { - AttemptedTxCount prometheus.Counter - SentTxCount prometheus.Counter - SuccessfulTxCount prometheus.Counter - CancelledTxCount prometheus.Counter - FailedTxCount prometheus.Counter - NotFoundDuringCancelCount prometheus.Counter - - LastUsedNonce prometheus.Gauge - LastConfirmedNonce prometheus.Gauge - CurrentBlockNumber prometheus.Gauge - GetReceiptBatchOperationTimeMs prometheus.Gauge -} - -func newMetrics() *metrics { - m := &metrics{ - AttemptedTxCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "attempted_tx_count", - Help: "Number of attempted transactions", - }), - SentTxCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "sent_tx_count", - Help: "Number of sent transactions", - }), - SuccessfulTxCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "successful_tx_count", - Help: "Number of successful transactions", - }), - CancelledTxCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "cancelled_tx_count", - Help: "Number of cancelled transactions", - }), - FailedTxCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "failed_tx_count", - Help: "Number of failed transactions", - }), - NotFoundDuringCancelCount: prometheus.NewCounter(prometheus.CounterOpts{ - Namespace: defaultMetricsNamespace, - Name: "not_found_during_cancel_count", - Help: "Number of transactions not found during cancel", - }), - LastUsedNonce: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: defaultMetricsNamespace, - Name: "last_used_nonce", - Help: "Last used nonce", - }), - LastConfirmedNonce: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: defaultMetricsNamespace, - Name: "last_confirmed_nonce", - Help: "Last confirmed nonce", - }), - CurrentBlockNumber: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: defaultMetricsNamespace, - Name: "current_block_number", - Help: "Current block number at which the node is checking", - }), - GetReceiptBatchOperationTimeMs: prometheus.NewGauge(prometheus.GaugeOpts{ - Namespace: defaultMetricsNamespace, - Name: "get_receipt_batch_operation_time_ms", - Help: "Time taken to get receipts in a batch", - }), - } - - return m -} - -func (m *metrics) collectors() []prometheus.Collector { - return []prometheus.Collector{ - m.AttemptedTxCount, - m.SentTxCount, - m.SuccessfulTxCount, - m.CancelledTxCount, - m.FailedTxCount, - m.NotFoundDuringCancelCount, - m.LastUsedNonce, - m.LastConfirmedNonce, - m.CurrentBlockNumber, - m.GetReceiptBatchOperationTimeMs, - } -} diff --git a/p2p/pkg/evmclient/mock/mock.go b/p2p/pkg/evmclient/mock/mock.go deleted file mode 100644 index 1bdc9649b..000000000 --- a/p2p/pkg/evmclient/mock/mock.go +++ /dev/null @@ -1,166 +0,0 @@ -package mockevmclient - -import ( - "context" - "errors" - "math/big" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/primev/mev-commit/p2p/pkg/evmclient" -) - -type Option func(*mockEvmClient) - -func New(opts ...Option) *mockEvmClient { - m := &mockEvmClient{} - for _, opt := range opts { - opt(m) - } - return m -} - -func WithSendFunc( - f func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error), -) Option { - return func(m *mockEvmClient) { - m.SendFunc = f - } -} - -func WithWaitForReceiptFunc( - f func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error), -) Option { - return func(m *mockEvmClient) { - m.WaitForReceiptFunc = f - } -} - -func WithCallFunc( - f func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error), -) Option { - return func(m *mockEvmClient) { - m.CallFunc = f - } -} - -func WithCancelFunc( - f func(ctx context.Context, txHash common.Hash) (common.Hash, error), -) Option { - return func(m *mockEvmClient) { - m.CancelFunc = f - } -} - -func WithSubscribeFilterLogs( - f func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error), -) Option { - return func(m *mockEvmClient) { - m.SubscribeFilterLogsFunc = f - } -} - -func WithBlockByNumber( - f func(ctx context.Context, number *big.Int) (*types.Block, error), -) Option { - return func(m *mockEvmClient) { - m.BlockByNumberFunc = f - } -} - -func WithBlockNumber( - f func(ctx context.Context) (uint64, error), -) Option { - return func(m *mockEvmClient) { - m.BlockNumberFunc = f - } -} - -func WithFilterLogs( - f func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error), -) Option { - return func(m *mockEvmClient) { - m.FilterLogsFunc = f - } -} - -type mockEvmClient struct { - SendFunc func(ctx context.Context, req *evmclient.TxRequest) (common.Hash, error) - WaitForReceiptFunc func(ctx context.Context, txnHash common.Hash) (*types.Receipt, error) - CallFunc func(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) - CancelFunc func(ctx context.Context, txHash common.Hash) (common.Hash, error) - SubscribeFilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) - BlockByNumberFunc func(ctx context.Context, number *big.Int) (*types.Block, error) - BlockNumberFunc func(ctx context.Context) (uint64, error) - FilterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) -} - -func (m *mockEvmClient) BlockNumber(ctx context.Context) (uint64, error) { - if m.BlockNumberFunc == nil { - return 0, errors.New("not implemented") - } - return m.BlockNumberFunc(ctx) -} - -func (m *mockEvmClient) Send( - ctx context.Context, - req *evmclient.TxRequest, -) (common.Hash, error) { - if m.SendFunc == nil { - return common.Hash{}, errors.New("not implemented") - } - return m.SendFunc(ctx, req) -} - -func (m *mockEvmClient) WaitForReceipt( - ctx context.Context, - txnHash common.Hash, -) (*types.Receipt, error) { - if m.WaitForReceiptFunc == nil { - return nil, errors.New("not implemented") - } - return m.WaitForReceiptFunc(ctx, txnHash) -} - -func (m *mockEvmClient) Call(ctx context.Context, req *evmclient.TxRequest) ([]byte, error) { - if m.CallFunc == nil { - return nil, errors.New("not implemented") - } - return m.CallFunc(ctx, req) -} - -func (m *mockEvmClient) CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) { - if m.CancelFunc == nil { - return common.Hash{}, errors.New("not implemented") - } - return m.CancelFunc(ctx, txHash) -} - -func (m *mockEvmClient) SubscribeFilterLogs( - ctx context.Context, - query ethereum.FilterQuery, - ch chan<- types.Log, -) (ethereum.Subscription, error) { - if m.SubscribeFilterLogsFunc == nil { - return nil, errors.New("not implemented") - } - return m.SubscribeFilterLogsFunc(ctx, query, ch) -} - -func (m *mockEvmClient) BlockByNumber( - ctx context.Context, - number *big.Int, -) (*types.Block, error) { - if m.BlockByNumberFunc == nil { - return nil, errors.New("not implemented") - } - return m.BlockByNumber(ctx, number) -} - -func (m *mockEvmClient) FilterLogs(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) { - if m.FilterLogsFunc == nil { - return nil, errors.New("not implemented") - } - return m.FilterLogsFunc(ctx, query) -} diff --git a/p2p/pkg/evmclient/mockevm/mockevm.go b/p2p/pkg/evmclient/mockevm/mockevm.go deleted file mode 100644 index 20a298720..000000000 --- a/p2p/pkg/evmclient/mockevm/mockevm.go +++ /dev/null @@ -1,255 +0,0 @@ -package mockevm - -import ( - "context" - "errors" - "math/big" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rpc" - "github.com/primev/mev-commit/p2p/pkg/evmclient" -) - -type mockEvm struct { - networkID *big.Int - batcherFunc func() evmclient.Batcher - blockNumFunc func(ctx context.Context) (uint64, error) - blockByNumberFunc func(ctx context.Context, blockNumber *big.Int) (*types.Block, error) - pendingNonceAtFunc func(ctx context.Context, account common.Address) (uint64, error) - nonceAtFunc func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) - suggestGasPriceFunc func(ctx context.Context) (*big.Int, error) - suggestGasTipCapFunc func(ctx context.Context) (*big.Int, error) - estimateGasFunc func(ctx context.Context, call ethereum.CallMsg) (uint64, error) - sendTransactionFunc func(ctx context.Context, tx *types.Transaction) error - callContractFunc func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error) - transactionReceiptFunc func(ctx context.Context, txHash common.Hash) (*types.Receipt, error) - transactionByHasFunc func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error) - subscribeLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error) - filterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error) -} - -type Option func(*mockEvm) - -type batchFunc func(context.Context, []rpc.BatchElem) error - -func (b batchFunc) BatchCallContext(ctx context.Context, batch []rpc.BatchElem) error { - return b(ctx, batch) -} - -func WithBatcherFunc(batcherFunc func(context.Context, []rpc.BatchElem) error) Option { - return func(m *mockEvm) { - m.batcherFunc = func() evmclient.Batcher { - return batchFunc(batcherFunc) - } - } -} - -func WithBlockNumFunc(blockNumFunc func(ctx context.Context) (uint64, error)) Option { - return func(m *mockEvm) { - m.blockNumFunc = blockNumFunc - } -} - -func WithBlockByNumberFunc(blockByNumberFunc func(ctx context.Context, blockNumber *big.Int) (*types.Block, error)) Option { - return func(m *mockEvm) { - m.blockByNumberFunc = blockByNumberFunc - } -} - -func WithPendingNonceAtFunc(pendingNonceAtFunc func(ctx context.Context, account common.Address) (uint64, error)) Option { - return func(m *mockEvm) { - m.pendingNonceAtFunc = pendingNonceAtFunc - } -} - -func WithNonceAtFunc(nonceAtFunc func(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error)) Option { - return func(m *mockEvm) { - m.nonceAtFunc = nonceAtFunc - } -} - -func WithSuggestGasPriceFunc(suggestGasPriceFunc func(ctx context.Context) (*big.Int, error)) Option { - return func(m *mockEvm) { - m.suggestGasPriceFunc = suggestGasPriceFunc - } -} - -func WithSuggestGasTipCapFunc(suggestGasTipCapFunc func(ctx context.Context) (*big.Int, error)) Option { - return func(m *mockEvm) { - m.suggestGasTipCapFunc = suggestGasTipCapFunc - } -} - -func WithEstimateGasFunc(estimateGasFunc func(ctx context.Context, call ethereum.CallMsg) (uint64, error)) Option { - return func(m *mockEvm) { - m.estimateGasFunc = estimateGasFunc - } -} - -func WithSendTransactionFunc(sendTransactionFunc func(ctx context.Context, tx *types.Transaction) error) Option { - return func(m *mockEvm) { - m.sendTransactionFunc = sendTransactionFunc - } -} - -func WithCallContractFunc(callContractFunc func(ctx context.Context, call ethereum.CallMsg, blockNumber *big.Int) ([]byte, error)) Option { - return func(m *mockEvm) { - m.callContractFunc = callContractFunc - } -} - -func WithTransactionReceiptFunc(transactionReceiptFunc func(ctx context.Context, txHash common.Hash) (*types.Receipt, error)) Option { - return func(m *mockEvm) { - m.transactionReceiptFunc = transactionReceiptFunc - } -} - -func WithTransactionByHashFunc(transactionByHashFunc func(ctx context.Context, txHash common.Hash) (*types.Transaction, bool, error)) Option { - return func(m *mockEvm) { - m.transactionByHasFunc = transactionByHashFunc - } -} - -func WithSubscribeLogsFunc(subscribeLogsFunc func(ctx context.Context, query ethereum.FilterQuery, ch chan<- types.Log) (ethereum.Subscription, error)) Option { - return func(m *mockEvm) { - m.subscribeLogsFunc = subscribeLogsFunc - } -} - -func WithFilterLogs(filterLogsFunc func(ctx context.Context, query ethereum.FilterQuery) ([]types.Log, error)) Option { - return func(m *mockEvm) { - m.filterLogsFunc = filterLogsFunc - } -} - -func NewMockEvm(networkID uint64, opts ...Option) *mockEvm { - m := &mockEvm{} - for _, opt := range opts { - opt(m) - } - m.networkID = new(big.Int).SetUint64(networkID) - return m -} - -var ErrNotImplemented = errors.New("not implemented") - -func (m *mockEvm) Batcher() evmclient.Batcher { - if m.batcherFunc != nil { - return m.batcherFunc() - } - return nil -} - -func (m *mockEvm) NetworkID(ctx context.Context) (*big.Int, error) { - return m.networkID, nil -} - -func (m *mockEvm) BlockNumber(ctx context.Context) (uint64, error) { - if m.blockNumFunc != nil { - return m.blockNumFunc(ctx) - } - return 0, ErrNotImplemented -} - -func (m *mockEvm) BlockByNumber(ctx context.Context, blockNumber *big.Int) (*types.Block, error) { - if m.blockByNumberFunc != nil { - return m.blockByNumberFunc(ctx, blockNumber) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) PendingNonceAt(ctx context.Context, account common.Address) (uint64, error) { - if m.pendingNonceAtFunc != nil { - return m.pendingNonceAtFunc(ctx, account) - } - return 0, ErrNotImplemented -} - -func (m *mockEvm) NonceAt(ctx context.Context, account common.Address, blockNumber *big.Int) (uint64, error) { - if m.nonceAtFunc != nil { - return m.nonceAtFunc(ctx, account, blockNumber) - } - return 0, ErrNotImplemented -} - -func (m *mockEvm) SuggestGasPrice(ctx context.Context) (*big.Int, error) { - if m.suggestGasPriceFunc != nil { - return m.suggestGasPriceFunc(ctx) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) SuggestGasTipCap(ctx context.Context) (*big.Int, error) { - if m.suggestGasTipCapFunc != nil { - return m.suggestGasTipCapFunc(ctx) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) EstimateGas(ctx context.Context, call ethereum.CallMsg) (uint64, error) { - if m.estimateGasFunc != nil { - return m.estimateGasFunc(ctx, call) - } - return 0, ErrNotImplemented -} - -func (m *mockEvm) SendTransaction(ctx context.Context, tx *types.Transaction) error { - if m.sendTransactionFunc != nil { - return m.sendTransactionFunc(ctx, tx) - } - return ErrNotImplemented -} - -func (m *mockEvm) CallContract( - ctx context.Context, - call ethereum.CallMsg, - blockNumber *big.Int, -) ([]byte, error) { - if m.callContractFunc != nil { - return m.callContractFunc(ctx, call, blockNumber) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) TransactionReceipt( - ctx context.Context, - txHash common.Hash, -) (*types.Receipt, error) { - if m.transactionReceiptFunc != nil { - return m.transactionReceiptFunc(ctx, txHash) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) TransactionByHash( - ctx context.Context, - txHash common.Hash, -) (*types.Transaction, bool, error) { - if m.transactionByHasFunc != nil { - return m.transactionByHasFunc(ctx, txHash) - } - return nil, false, ErrNotImplemented -} - -func (m *mockEvm) SubscribeFilterLogs( - ctx context.Context, - query ethereum.FilterQuery, - ch chan<- types.Log, -) (ethereum.Subscription, error) { - if m.subscribeLogsFunc != nil { - return m.subscribeLogsFunc(ctx, query, ch) - } - return nil, ErrNotImplemented -} - -func (m *mockEvm) FilterLogs( - ctx context.Context, - query ethereum.FilterQuery, -) ([]types.Log, error) { - if m.filterLogsFunc != nil { - return m.filterLogsFunc(ctx, query) - } - return nil, ErrNotImplemented -} diff --git a/p2p/pkg/evmclient/txmonitor.go b/p2p/pkg/evmclient/txmonitor.go deleted file mode 100644 index d881ba39d..000000000 --- a/p2p/pkg/evmclient/txmonitor.go +++ /dev/null @@ -1,303 +0,0 @@ -package evmclient - -import ( - "context" - "errors" - "log/slog" - "math/big" - "sync" - "sync/atomic" - "time" - - "github.com/ethereum/go-ethereum" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/rpc" -) - -var ( - maxSentTxs uint64 = 1024 - batchSize int = 64 -) - -var ( - ErrTxnCancelled = errors.New("transaction was cancelled") - ErrMonitorClosed = errors.New("monitor was closed") -) - -type waitCheck struct { - nonce uint64 - block uint64 -} - -type txmonitor struct { - baseCtx context.Context - baseCancel context.CancelFunc - owner common.Address - mtx sync.Mutex - waitMap map[uint64]map[common.Hash][]chan Result - client EVM - newTxAdded chan struct{} - waitDone chan struct{} - checkerDone chan struct{} - blockUpdate chan waitCheck - logger *slog.Logger - metrics *metrics - lastConfirmedNonce atomic.Uint64 -} - -func newTxMonitor( - owner common.Address, - client EVM, - logger *slog.Logger, - m *metrics, -) *txmonitor { - baseCtx, baseCancel := context.WithCancel(context.Background()) - if m == nil { - m = newMetrics() - } - tm := &txmonitor{ - baseCtx: baseCtx, - baseCancel: baseCancel, - owner: owner, - client: client, - logger: logger, - metrics: m, - waitMap: make(map[uint64]map[common.Hash][]chan Result), - newTxAdded: make(chan struct{}), - waitDone: make(chan struct{}), - checkerDone: make(chan struct{}), - blockUpdate: make(chan waitCheck), - } - go tm.watchLoop() - go tm.checkLoop() - - return tm -} - -type Result struct { - Receipt *types.Receipt - Err error -} - -func (t *txmonitor) watchLoop() { - defer close(t.waitDone) - - queryTicker := time.NewTicker(500 * time.Millisecond) - defer queryTicker.Stop() - - defer func() { - t.mtx.Lock() - defer t.mtx.Unlock() - - for _, v := range t.waitMap { - for _, c := range v { - for _, c := range c { - c <- Result{nil, ErrMonitorClosed} - close(c) - } - } - } - }() - - lastBlock := uint64(0) - for { - newTx := false - select { - case <-t.baseCtx.Done(): - return - case <-t.newTxAdded: - newTx = true - case <-queryTicker.C: - } - - currentBlock, err := t.client.BlockNumber(t.baseCtx) - if err != nil { - t.logger.Error("failed to get block number", "err", err) - continue - } - - if currentBlock <= lastBlock && !newTx { - continue - } - - t.metrics.CurrentBlockNumber.Set(float64(currentBlock)) - - lastNonce, err := t.client.NonceAt( - t.baseCtx, - t.owner, - new(big.Int).SetUint64(currentBlock), - ) - if err != nil { - t.logger.Error("failed to get nonce", "err", err) - continue - } - - t.lastConfirmedNonce.Store(lastNonce) - t.metrics.LastConfirmedNonce.Set(float64(lastNonce)) - - select { - case t.blockUpdate <- waitCheck{lastNonce, currentBlock}: - default: - } - lastBlock = currentBlock - } -} - -func (t *txmonitor) checkLoop() { - defer close(t.checkerDone) - - for { - select { - case <-t.baseCtx.Done(): - return - case check := <-t.blockUpdate: - t.check(check.block, check.nonce) - } - } -} - -func (t *txmonitor) Close() error { - t.baseCancel() - done := make(chan struct{}) - go func() { - <-t.checkerDone - <-t.waitDone - - close(done) - }() - - select { - case <-done: - return nil - case <-time.After(10 * time.Second): - return errors.New("failed to close txmonitor") - } -} - -func (t *txmonitor) getOlderTxns(nonce uint64) map[uint64][]common.Hash { - t.mtx.Lock() - defer t.mtx.Unlock() - - txnMap := make(map[uint64][]common.Hash) - for k, v := range t.waitMap { - if k >= nonce { - continue - } - - for h := range v { - txnMap[k] = append(txnMap[k], h) - } - } - - return txnMap -} - -func (t *txmonitor) notify( - nonce uint64, - txn common.Hash, - res Result, -) { - t.mtx.Lock() - defer t.mtx.Unlock() - - waiters := 0 - for _, c := range t.waitMap[nonce][txn] { - c <- res - waiters++ - close(c) - } - delete(t.waitMap[nonce], txn) - if len(t.waitMap[nonce]) == 0 { - delete(t.waitMap, nonce) - } -} - -func (t *txmonitor) check(newBlock uint64, lastNonce uint64) { - checkTxns := t.getOlderTxns(lastNonce) - nonceMap := make(map[common.Hash]uint64) - - if len(checkTxns) == 0 { - return - } - - txHashes := make([]common.Hash, 0, len(checkTxns)) - for n, txns := range checkTxns { - for _, txn := range txns { - txHashes = append(txHashes, txn) - nonceMap[txn] = n - } - } - - for start := 0; start < len(txHashes); start += batchSize { - end := start + batchSize - if end > len(txHashes) { - end = len(txHashes) - } - - // Prepare the batch - batch := make([]rpc.BatchElem, end-start) - for i, hash := range txHashes[start:end] { - batch[i] = rpc.BatchElem{ - Method: "eth_getTransactionReceipt", - Args: []interface{}{hash}, - Result: new(types.Receipt), - } - } - - opStart := time.Now() - // Execute the batch request - err := t.client.Batcher().BatchCallContext(t.baseCtx, batch) - if err != nil { - t.logger.Error("failed to execute batch call", "err", err) - return - } - t.metrics.GetReceiptBatchOperationTimeMs.Set(float64(time.Since(opStart).Milliseconds())) - - // Process the responses - for i, result := range batch { - tHash := txHashes[start+i] - nonce := nonceMap[tHash] - if result.Error != nil { - if errors.Is(result.Error, ethereum.NotFound) { - t.notify(nonce, tHash, Result{nil, ErrTxnCancelled}) - continue - } - var tt *TransactionTrace - if dbg, ok := t.client.(Debugger); ok { - if tt, err = dbg.TraceTransaction(t.baseCtx, tHash); err != nil { - t.logger.Error("retrieving transaction trace failed", "error", err) - } - } - t.logger.Error("failed to get receipt", "error", result.Error, "transaction_trace", tt) - continue - } - if result.Result == nil { - continue - } - t.notify(nonce, tHash, Result{result.Result.(*types.Receipt), nil}) - } - } -} - -func (t *txmonitor) allowNonce(nonce uint64) bool { - return nonce <= t.lastConfirmedNonce.Load()+maxSentTxs -} - -func (t *txmonitor) watchTx(txHash common.Hash, nonce uint64) (<-chan Result, error) { - t.mtx.Lock() - defer t.mtx.Unlock() - - if t.waitMap[nonce] == nil { - t.waitMap[nonce] = make(map[common.Hash][]chan Result) - } - - c := make(chan Result, 1) - t.waitMap[nonce][txHash] = append(t.waitMap[nonce][txHash], c) - - select { - case t.newTxAdded <- struct{}{}: - default: - } - return c, nil -} diff --git a/p2p/pkg/node/node.go b/p2p/pkg/node/node.go index 4cd09e861..710ce24d3 100644 --- a/p2p/pkg/node/node.go +++ b/p2p/pkg/node/node.go @@ -21,24 +21,23 @@ import ( bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" blocktracker "github.com/primev/mev-commit/contracts-abi/clients/BlockTracker" preconf "github.com/primev/mev-commit/contracts-abi/clients/PreConfCommitmentStore" + preconfcommitmentstore "github.com/primev/mev-commit/contracts-abi/clients/PreConfCommitmentStore" + providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" bidderapiv1 "github.com/primev/mev-commit/p2p/gen/go/bidderapi/v1" + debugapiv1 "github.com/primev/mev-commit/p2p/gen/go/debugapi/v1" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" "github.com/primev/mev-commit/p2p/pkg/apiserver" - bidder_registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/bidder_registry" - preconfcontract "github.com/primev/mev-commit/p2p/pkg/contracts/preconf" - provider_registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/provider_registry" "github.com/primev/mev-commit/p2p/pkg/crypto" - "github.com/primev/mev-commit/p2p/pkg/debugapi" "github.com/primev/mev-commit/p2p/pkg/depositmanager" "github.com/primev/mev-commit/p2p/pkg/discovery" - "github.com/primev/mev-commit/p2p/pkg/evmclient" "github.com/primev/mev-commit/p2p/pkg/keyexchange" "github.com/primev/mev-commit/p2p/pkg/p2p" "github.com/primev/mev-commit/p2p/pkg/p2p/libp2p" "github.com/primev/mev-commit/p2p/pkg/preconfirmation" preconftracker "github.com/primev/mev-commit/p2p/pkg/preconfirmation/tracker" bidderapi "github.com/primev/mev-commit/p2p/pkg/rpc/bidder" + debugapi "github.com/primev/mev-commit/p2p/pkg/rpc/debug" providerapi "github.com/primev/mev-commit/p2p/pkg/rpc/provider" "github.com/primev/mev-commit/p2p/pkg/signer" "github.com/primev/mev-commit/p2p/pkg/signer/preconfencryptor" @@ -111,40 +110,100 @@ func NewNode(opts *Options) (*Node, error) { } } - evmClient, err := evmclient.New( - opts.KeySigner, - evmclient.WrapEthClient(contractRPC), - opts.Logger.With("component", "evmclient"), - ) + chainID, err := contractRPC.ChainID(context.Background()) + if err != nil { + opts.Logger.Error("failed to get chain ID", "error", err) + return nil, err + } + + store := store.NewStore() + + contracts, err := getContractABIs(opts) if err != nil { - opts.Logger.Error("failed to create evm client", "error", err) + opts.Logger.Error("failed to get contract ABIs", "error", err) return nil, err } - nd.closers = append(nd.closers, evmClient) - srv.MetricsRegistry().MustRegister(evmClient.Metrics()...) - bidderRegistryContractAddr := common.HexToAddress(opts.BidderRegistryContract) - bidderRegistry := bidder_registrycontract.New( + abis := make([]*abi.ABI, 0, len(contracts)) + contractAddrs := make([]common.Address, 0, len(contracts)) + + for addr, abi := range contracts { + abis = append(abis, abi) + contractAddrs = append(contractAddrs, addr) + } + + evtMgr := events.NewListener( + opts.Logger.With("component", "events"), + abis..., + ) + + var startables []Startable + var evtPublisher PublisherStartable + + if opts.WSRPCEndpoint != "" { + // Use WS publisher if WSRPCEndpoint is set + evtPublisher = publisher.NewWSPublisher( + store, + opts.Logger.With("component", "ws_publisher"), + contractRPC, + evtMgr, + ) + } else { + evtPublisher = publisher.NewHTTPPublisher( + store, + opts.Logger.With("component", "http_publisher"), + contractRPC, + evtMgr, + ) + } + + startables = append( + startables, + StartableFunc(func(ctx context.Context) <-chan struct{} { + return evtPublisher.Start(ctx, contractAddrs...) + }), + ) + + monitor := txmonitor.New( opts.KeySigner.GetAddress(), - bidderRegistryContractAddr, - evmClient, - opts.Logger.With("component", "bidderregistry"), + contractRPC, + txmonitor.NewEVMHelper(contractRPC.Client()), + store, + opts.Logger.With("component", "txmonitor"), + 256, ) + startables = append(startables, monitor) - providerRegistryContractAddr := common.HexToAddress(opts.ProviderRegistryContract) - providerRegistry := provider_registrycontract.New( - providerRegistryContractAddr, - evmClient, - opts.Logger.With("component", "providerregistry"), + providerRegistry, err := providerregistry.NewProviderregistry( + common.HexToAddress(opts.ProviderRegistryContract), + contractRPC, ) + if err != nil { + opts.Logger.Error("failed to instantiate provider registry contract", "error", err) + return nil, err + } - store := store.NewStore() + bidderRegistry, err := bidderregistry.NewBidderregistry( + common.HexToAddress(opts.BidderRegistryContract), + contractRPC, + ) + if err != nil { + opts.Logger.Error("failed to instantiate bidder registry contract", "error", err) + return nil, err + } + + optsGetter := func(ctx context.Context) (*bind.TransactOpts, error) { + return opts.KeySigner.GetAuthWithCtx(ctx, chainID) + } p2pSvc, err := libp2p.New(&libp2p.Options{ - KeySigner: opts.KeySigner, - Secret: opts.Secret, - PeerType: peerType, - Register: providerRegistry, + KeySigner: opts.KeySigner, + Secret: opts.Secret, + PeerType: peerType, + Register: &providerStakeChecker{ + providerRegistry: providerRegistry, + from: opts.KeySigner.GetAddress(), + }, Store: store, Logger: opts.Logger.With("component", "p2p"), ListenPort: opts.P2PPort, @@ -173,82 +232,51 @@ func NewNode(opts *Options) (*Node, error) { // Register the discovery protocol with the p2p service p2pSvc.AddStreamHandlers(disc.Streams()...) - debugapi.RegisterAPI(srv, topo, p2pSvc, opts.Logger.With("component", "debugapi")) - - ctx, cancel := context.WithCancel(context.Background()) - - contracts, err := getContractABIs(opts) + lis, err := net.Listen("tcp", opts.RPCAddr) if err != nil { - opts.Logger.Error("failed to get contract ABIs", "error", err) - cancel() - return nil, err + opts.Logger.Error("failed to listen", "error", err) + return nil, errors.Join(err, nd.Close()) } - abis := make([]*abi.ABI, 0, len(contracts)) - contractAddrs := make([]common.Address, 0, len(contracts)) - - for addr, abi := range contracts { - abis = append(abis, abi) - contractAddrs = append(contractAddrs, addr) - } - - evtMgr := events.NewListener( - opts.Logger.With("component", "events"), - abis..., - ) - - var evtPublisher Starter - if opts.WSRPCEndpoint != "" { - // Use WS publisher if WSRPCEndpoint is set - evtPublisher = publisher.NewWSPublisher( - testStore{}, - opts.Logger.With("component", "ws_publisher"), - contractRPC, - evtMgr, - ) - } else { - evtPublisher = publisher.NewHTTPPublisher( - testStore{}, - opts.Logger.With("component", "http_publisher"), - contractRPC, - evtMgr, + var tlsCredentials credentials.TransportCredentials + if opts.TLSCertificateFile != "" && opts.TLSPrivateKeyFile != "" { + tlsCredentials, err = credentials.NewServerTLSFromFile( + opts.TLSCertificateFile, + opts.TLSPrivateKeyFile, ) - } - - if opts.PeerType != p2p.PeerTypeBootnode.String() { - lis, err := net.Listen("tcp", opts.RPCAddr) if err != nil { - opts.Logger.Error("failed to listen", "error", err) - cancel() - return nil, errors.Join(err, nd.Close()) + opts.Logger.Error("failed to load TLS credentials", "error", err) + return nil, fmt.Errorf("unable to load TLS credentials: %w", err) } + } - var tlsCredentials credentials.TransportCredentials - if opts.TLSCertificateFile != "" && opts.TLSPrivateKeyFile != "" { - tlsCredentials, err = credentials.NewServerTLSFromFile( - opts.TLSCertificateFile, - opts.TLSPrivateKeyFile, - ) - if err != nil { - opts.Logger.Error("failed to load TLS credentials", "error", err) - cancel() - return nil, fmt.Errorf("unable to load TLS credentials: %w", err) - } - } + grpcServer := grpc.NewServer(grpc.Creds(tlsCredentials)) + + debugService := debugapi.NewService( + store, + txmonitor.NewCanceller( + chainID, + contractRPC, + opts.KeySigner, + monitor, + opts.Logger.With("component", "txmonitor/canceller"), + ), + p2pSvc, + topo, + ) - grpcServer := grpc.NewServer(grpc.Creds(tlsCredentials)) + debugapiv1.RegisterDebugServiceServer(grpcServer, debugService) + if opts.PeerType != p2p.PeerTypeBootnode.String() { preconfEncryptor, err := preconfencryptor.NewEncryptor(opts.KeySigner, store) if err != nil { opts.Logger.Error("failed to create preconf encryptor", "error", err) - cancel() return nil, errors.Join(err, nd.Close()) } validator, err := protovalidate.New() if err != nil { opts.Logger.Error("failed to create proto validator", "error", err) - cancel() return nil, errors.Join(err, nd.Close()) } @@ -257,15 +285,12 @@ func NewNode(opts *Options) (*Node, error) { depositMgr preconfirmation.DepositManager = noOpDepositManager{} ) - blockTrackerAddr := common.HexToAddress(opts.BlockTrackerContract) - blockTrackerCaller, err := blocktracker.NewBlocktrackerCaller( - blockTrackerAddr, + common.HexToAddress(opts.BlockTrackerContract), contractRPC, ) if err != nil { opts.Logger.Error("failed to instantiate block tracker contract", "error", err) - cancel() return nil, err } @@ -276,13 +301,14 @@ func NewNode(opts *Options) (*Node, error) { }, } - preconfContractAddr := common.HexToAddress(opts.PreconfContract) - commitmentDA := preconfcontract.New( - preconfContractAddr, - evmClient, - opts.Logger.With("component", "preconfcontract"), + commitmentDA, err := preconfcommitmentstore.NewPreconfcommitmentstore( + common.HexToAddress(opts.PreconfContract), + contractRPC, ) - opts.Logger.Info("registered preconf contract") + if err != nil { + opts.Logger.Error("failed to instantiate preconf commitment store contract", "error", err) + return nil, err + } tracker := preconftracker.NewTracker( peerType, @@ -290,9 +316,10 @@ func NewNode(opts *Options) (*Node, error) { store, commitmentDA, txmonitor.NewEVMHelper(contractRPC.Client()), + optsGetter, opts.Logger.With("component", "tracker"), ) - nd.closers = append(nd.closers, channelCloserFunc(tracker.Start(ctx))) + startables = append(startables, tracker) switch opts.PeerType { case p2p.PeerTypeProvider.String(): @@ -300,7 +327,8 @@ func NewNode(opts *Options) (*Node, error) { opts.Logger.With("component", "providerapi"), providerRegistry, opts.KeySigner.GetAddress(), - evmClient, + monitor, + optsGetter, validator, ) providerapiv1.RegisterProviderServer(grpcServer, providerAPI) @@ -312,12 +340,8 @@ func NewNode(opts *Options) (*Node, error) { evtMgr, opts.Logger.With("component", "depositmanager"), ) - nd.closers = append( - nd.closers, - channelCloserFunc(depositMgr.(*depositmanager.DepositManager).Start(ctx)), - ) + startables = append(startables, depositMgr.(*depositmanager.DepositManager)) preconfProto := preconfirmation.New( - opts.KeySigner.GetAddress(), topo, p2pSvc, preconfEncryptor, @@ -325,6 +349,7 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, tracker, + optsGetter, opts.Logger.With("component", "preconfirmation_protocol"), ) @@ -344,7 +369,6 @@ func NewNode(opts *Options) (*Node, error) { case p2p.PeerTypeBidder.String(): preconfProto := preconfirmation.New( - opts.KeySigner.GetAddress(), topo, p2pSvc, preconfEncryptor, @@ -352,17 +376,20 @@ func NewNode(opts *Options) (*Node, error) { bidProcessor, commitmentDA, tracker, + optsGetter, opts.Logger.With("component", "preconfirmation_protocol"), ) srv.RegisterMetricsCollectors(preconfProto.Metrics()...) bidderAPI := bidderapi.NewService( - preconfProto, opts.KeySigner.GetAddress(), + preconfProto, bidderRegistry, blockTrackerSession, validator, + monitor, + optsGetter, opts.Logger.With("component", "bidderapi"), ) bidderapiv1.RegisterBidderServer(grpcServer, bidderAPI) @@ -370,13 +397,11 @@ func NewNode(opts *Options) (*Node, error) { aesKey, err := crypto.GenerateAESKey() if err != nil { opts.Logger.Error("failed to generate AES key", "error", err) - cancel() return nil, errors.Join(err, nd.Close()) } err = store.SetAESKey(opts.KeySigner.GetAddress(), aesKey) if err != nil { opts.Logger.Error("failed to set AES key", "error", err) - cancel() return nil, errors.Join(err, nd.Close()) } @@ -400,100 +425,103 @@ func NewNode(opts *Options) (*Node, error) { srv.RegisterMetricsCollectors(bidderAPI.Metrics()...) } + } - started := make(chan struct{}) - go func() { - // signal that the server has started - close(started) - - err := grpcServer.Serve(lis) - if err != nil { - opts.Logger.Error("failed to start grpc server", "err", err) - } - }() - nd.closers = append(nd.closers, lis) - - // Wait for the server to start - <-started - - // Since we don't know if the server has TLS enabled on its rpc - // endpoint, we try different strategies from most secure to - // least secure. In the future, when only TLS-enabled servers - // are allowed, only the TLS system pool certificate strategy - // should be used. - var grpcConn *grpc.ClientConn - for _, e := range []struct { - strategy string - isSecure bool - credential credentials.TransportCredentials - }{ - {"TLS system pool certificate", true, credentials.NewClientTLSFromCert(nil, "")}, - {"TLS skip verification", false, credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})}, - {"TLS disabled", false, insecure.NewCredentials()}, - } { - ctx, cancel := context.WithTimeout(context.Background(), grpcServerDialTimeout) - opts.Logger.Info("dialing to grpc server", "strategy", e.strategy) - // nolint:staticcheck - grpcConn, err = grpc.DialContext( - ctx, - opts.RPCAddr, - grpc.WithBlock(), - grpc.WithTransportCredentials(e.credential), - ) - if err != nil { - opts.Logger.Error("failed to dial grpc server", "error", err) - cancel() - continue - } + started := make(chan struct{}) + go func() { + // signal that the server has started + close(started) - cancel() - if !e.isSecure { - opts.Logger.Warn("established connection with the grpc server has potential security risk") - } - break + err := grpcServer.Serve(lis) + if err != nil { + opts.Logger.Error("failed to start grpc server", "err", err) } - if grpcConn == nil { + }() + nd.closers = append(nd.closers, lis) + + // Wait for the server to start + <-started + + // Since we don't know if the server has TLS enabled on its rpc + // endpoint, we try different strategies from most secure to + // least secure. In the future, when only TLS-enabled servers + // are allowed, only the TLS system pool certificate strategy + // should be used. + var grpcConn *grpc.ClientConn + for _, e := range []struct { + strategy string + isSecure bool + credential credentials.TransportCredentials + }{ + {"TLS system pool certificate", true, credentials.NewClientTLSFromCert(nil, "")}, + {"TLS skip verification", false, credentials.NewTLS(&tls.Config{InsecureSkipVerify: true})}, + {"TLS disabled", false, insecure.NewCredentials()}, + } { + ctx, cancel := context.WithTimeout(context.Background(), grpcServerDialTimeout) + opts.Logger.Info("dialing to grpc server", "strategy", e.strategy) + // nolint:staticcheck + grpcConn, err = grpc.DialContext( + ctx, + opts.RPCAddr, + grpc.WithBlock(), + grpc.WithTransportCredentials(e.credential), + ) + if err != nil { + opts.Logger.Error("failed to dial grpc server", "error", err) cancel() - return nil, errors.New("dialing of grpc server failed") + continue } - handlerCtx, handlerCancel := context.WithTimeout(context.Background(), 3*time.Second) - defer handlerCancel() - - gatewayMux := runtime.NewServeMux() - switch opts.PeerType { - case p2p.PeerTypeProvider.String(): - err := providerapiv1.RegisterProviderHandler(handlerCtx, gatewayMux, grpcConn) - if err != nil { - opts.Logger.Error("failed to register provider handler", "err", err) - cancel() - return nil, errors.Join(err, nd.Close()) - } - case p2p.PeerTypeBidder.String(): - err := bidderapiv1.RegisterBidderHandler(handlerCtx, gatewayMux, grpcConn) - if err != nil { - opts.Logger.Error("failed to register bidder handler", "err", err) - cancel() - return nil, errors.Join(err, nd.Close()) - } + cancel() + if !e.isSecure { + opts.Logger.Warn("established connection with the grpc server has potential security risk") } + break + } + if grpcConn == nil { + return nil, errors.New("dialing of grpc server failed") + } - srv.ChainHandlers("/", gatewayMux) - srv.ChainHandlers( - "/health", - http.HandlerFunc( - func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "text/plain") - if s := grpcConn.GetState(); s != connectivity.Ready { - http.Error(w, fmt.Sprintf("grpc server is %s", s), http.StatusBadGateway) - return - } - fmt.Fprintln(w, "ok") - }, - ), - ) + handlerCtx, handlerCancel := context.WithTimeout(context.Background(), 3*time.Second) + defer handlerCancel() + + gatewayMux := runtime.NewServeMux() + err = debugapiv1.RegisterDebugServiceHandler(handlerCtx, gatewayMux, grpcConn) + if err != nil { + opts.Logger.Error("failed to register debug handler", "err", err) + return nil, errors.Join(err, nd.Close()) } + switch opts.PeerType { + case p2p.PeerTypeProvider.String(): + err := providerapiv1.RegisterProviderHandler(handlerCtx, gatewayMux, grpcConn) + if err != nil { + opts.Logger.Error("failed to register provider handler", "err", err) + return nil, errors.Join(err, nd.Close()) + } + case p2p.PeerTypeBidder.String(): + err := bidderapiv1.RegisterBidderHandler(handlerCtx, gatewayMux, grpcConn) + if err != nil { + opts.Logger.Error("failed to register bidder handler", "err", err) + return nil, errors.Join(err, nd.Close()) + } + } + + srv.ChainHandlers("/", gatewayMux) + srv.ChainHandlers( + "/health", + http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + if s := grpcConn.GetState(); s != connectivity.Ready { + http.Error(w, fmt.Sprintf("grpc server is %s", s), http.StatusBadGateway) + return + } + fmt.Fprintln(w, "ok") + }, + ), + ) + server := &http.Server{ Addr: opts.HTTPAddr, Handler: srv.Router(), @@ -518,7 +546,12 @@ func NewNode(opts *Options) (*Node, error) { } }() nd.closers = append(nd.closers, server) - nd.closers = append(nd.closers, channelCloserFunc(evtPublisher.Start(ctx, contractAddrs...))) + + ctx, cancel := context.WithCancel(context.Background()) + + for _, s := range startables { + nd.closers = append(nd.closers, channelCloserFunc(s.Start(ctx))) + } nd.cancelFunc = cancel @@ -582,16 +615,6 @@ func (noOpDepositManager) CheckAndDeductDeposit(_ context.Context, _ common.Addr return func() error { return nil }, nil } -type testStore struct{} - -func (t testStore) LastBlock() (uint64, error) { - return 0, nil -} - -func (t testStore) SetLastBlock(_ uint64) error { - return nil -} - type channelCloser <-chan struct{} func channelCloserFunc(c <-chan struct{}) io.Closer { @@ -607,6 +630,40 @@ func (c channelCloser) Close() error { } } -type Starter interface { +type PublisherStartable interface { Start(ctx context.Context, contracts ...common.Address) <-chan struct{} } + +type Startable interface { + Start(ctx context.Context) <-chan struct{} +} + +type StartableFunc func(ctx context.Context) <-chan struct{} + +func (f StartableFunc) Start(ctx context.Context) <-chan struct{} { + return f(ctx) +} + +type providerStakeChecker struct { + providerRegistry *providerregistry.Providerregistry + from common.Address +} + +func (p *providerStakeChecker) CheckProviderRegistered(ctx context.Context, provider common.Address) bool { + callOpts := &bind.CallOpts{ + From: p.from, + Context: ctx, + } + + minStake, err := p.providerRegistry.MinStake(callOpts) + if err != nil { + return false + } + + stake, err := p.providerRegistry.CheckStake(callOpts, provider) + if err != nil { + return false + } + + return stake.Cmp(minStake) >= 0 +} diff --git a/p2p/pkg/p2p/libp2p/libp2p.go b/p2p/pkg/p2p/libp2p/libp2p.go index 27d6c009d..53da4d077 100644 --- a/p2p/pkg/p2p/libp2p/libp2p.go +++ b/p2p/pkg/p2p/libp2p/libp2p.go @@ -261,11 +261,16 @@ func (s *Service) disconnected(p p2p.Peer) { } func (s *Service) Self() map[string]interface{} { + addrStrings := make([]interface{}, 0, len(s.host.Addrs())) + for _, addr := range s.host.Addrs() { + addrStrings = append(addrStrings, addr.String()) + } + return map[string]interface{}{ "Ethereum Address": s.ethAddress.Hex(), "Peer Type": s.peerType.String(), "Underlay": s.host.ID().String(), - "Addresses": s.host.Addrs(), + "Addresses": addrStrings, } } diff --git a/p2p/pkg/preconfirmation/preconfirmation.go b/p2p/pkg/preconfirmation/preconfirmation.go index bf387e382..94b7c2efb 100644 --- a/p2p/pkg/preconfirmation/preconfirmation.go +++ b/p2p/pkg/preconfirmation/preconfirmation.go @@ -7,7 +7,9 @@ import ( "sync" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" "github.com/primev/mev-commit/p2p/pkg/p2p" @@ -25,7 +27,6 @@ const ( ) type Preconfirmation struct { - owner common.Address encryptor encryptor.Encryptor topo Topology streamer p2p.Streamer @@ -33,10 +34,13 @@ type Preconfirmation struct { processer BidProcessor commitmentDA PreconfContract tracker Tracker + optsGetter OptsGetter logger *slog.Logger metrics *metrics } +type OptsGetter func(context.Context) (*bind.TransactOpts, error) + type Topology interface { GetPeers(topology.Query) []p2p.Peer } @@ -60,15 +64,14 @@ type Tracker interface { type PreconfContract interface { StoreEncryptedCommitment( - ctx context.Context, - commitmentDigest []byte, + opts *bind.TransactOpts, + commitmentDigest [32]byte, commitmentSignature []byte, dispatchTimestamp uint64, - ) (common.Hash, error) + ) (*types.Transaction, error) } func New( - owner common.Address, topo Topology, streamer p2p.Streamer, encryptor encryptor.Encryptor, @@ -76,10 +79,10 @@ func New( processor BidProcessor, commitmentDA PreconfContract, tracker Tracker, + optsGetter OptsGetter, logger *slog.Logger, ) *Preconfirmation { return &Preconfirmation{ - owner: owner, topo: topo, streamer: streamer, encryptor: encryptor, @@ -87,6 +90,7 @@ func New( processer: processor, commitmentDA: commitmentDA, tracker: tracker, + optsGetter: optsGetter, logger: logger, metrics: newMetrics(), } @@ -307,9 +311,17 @@ func (p *Preconfirmation) handleBid( if err != nil { return status.Errorf(codes.Internal, "failed to send preconfirmation: %v", err) } - txnHash, err := p.commitmentDA.StoreEncryptedCommitment( - ctx, - encryptedPreConfirmation.Commitment, + var commitmentDigest [32]byte + copy(commitmentDigest[:], encryptedPreConfirmation.Commitment) + + opts, err := p.optsGetter(ctx) + if err != nil { + return status.Errorf(codes.Internal, "failed to get transact opts: %v", err) + } + + txn, err := p.commitmentDA.StoreEncryptedCommitment( + opts, + commitmentDigest, encryptedPreConfirmation.Signature, uint64(st.DispatchTimestamp), ) @@ -319,7 +331,7 @@ func (p *Preconfirmation) handleBid( } encryptedAndDecryptedPreconfirmation := &store.EncryptedPreConfirmationWithDecrypted{ - TxnHash: txnHash, + TxnHash: txn.Hash(), EncryptedPreConfirmation: encryptedPreConfirmation, PreConfirmation: preConfirmation, } diff --git a/p2p/pkg/preconfirmation/preconfirmation_test.go b/p2p/pkg/preconfirmation/preconfirmation_test.go index 7c85df082..d587e4acd 100644 --- a/p2p/pkg/preconfirmation/preconfirmation_test.go +++ b/p2p/pkg/preconfirmation/preconfirmation_test.go @@ -11,7 +11,9 @@ import ( "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto/ecies" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" @@ -83,12 +85,12 @@ func (t *testProcessor) ProcessBid( type testCommitmentDA struct{} func (t *testCommitmentDA) StoreEncryptedCommitment( - _ context.Context, - _ []byte, + _ *bind.TransactOpts, + _ [32]byte, _ []byte, _ uint64, -) (common.Hash, error) { - return common.Hash{}, nil +) (*types.Transaction, error) { + return types.NewTransaction(0, common.Address{}, nil, 0, nil, nil), nil } func newTestLogger(t *testing.T, w io.Writer) *slog.Logger { @@ -192,7 +194,6 @@ func TestPreconfBidSubmission(t *testing.T) { depositMgr := &testDepositManager{} p := preconfirmation.New( - client.EthAddress, topo, svc, signer, @@ -200,6 +201,11 @@ func TestPreconfBidSubmission(t *testing.T) { proc, &testCommitmentDA{}, &testTracker{}, + func(context.Context) (*bind.TransactOpts, error) { + return &bind.TransactOpts{ + From: client.EthAddress, + }, nil + }, newTestLogger(t, os.Stdout), ) diff --git a/p2p/pkg/preconfirmation/tracker/tracker.go b/p2p/pkg/preconfirmation/tracker/tracker.go index 7f822f61c..2d139612e 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker.go +++ b/p2p/pkg/preconfirmation/tracker/tracker.go @@ -4,9 +4,12 @@ import ( "context" "fmt" "log/slog" + "math/big" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" blocktracker "github.com/primev/mev-commit/contracts-abi/clients/BlockTracker" preconfcommstore "github.com/primev/mev-commit/contracts-abi/clients/PreConfCommitmentStore" "github.com/primev/mev-commit/p2p/pkg/p2p" @@ -22,6 +25,7 @@ type Tracker struct { store CommitmentStore preconfContract PreconfContract receiptGetter txmonitor.BatchReceiptGetter + optsGetter OptsGetter newL1Blocks chan *blocktracker.BlocktrackerNewL1Block enryptedCmts chan *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored commitments chan *preconfcommstore.PreconfcommitmentstoreCommitmentStored @@ -29,6 +33,8 @@ type Tracker struct { logger *slog.Logger } +type OptsGetter func(context.Context) (*bind.TransactOpts, error) + type CommitmentStore interface { GetCommitmentsByBlockNumber(blockNum int64) ([]*store.EncryptedPreConfirmationWithDecrypted, error) AddCommitment(commitment *store.EncryptedPreConfirmationWithDecrypted) @@ -39,17 +45,17 @@ type CommitmentStore interface { type PreconfContract interface { OpenCommitment( - ctx context.Context, - encryptedCommitmentIndex []byte, - bid string, - blockNumber int64, + opts *bind.TransactOpts, + encryptedCommitmentIndex [32]byte, + bid uint64, + blockNumber uint64, txnHash string, - decayStartTimeStamp int64, - decayEndTimeStamp int64, + decayStartTimeStamp uint64, + decayEndTimeStamp uint64, bidSignature []byte, commitmentSignature []byte, sharedSecretKey []byte, - ) (common.Hash, error) + ) (*types.Transaction, error) } func NewTracker( @@ -58,6 +64,7 @@ func NewTracker( store CommitmentStore, preconfContract PreconfContract, receiptGetter txmonitor.BatchReceiptGetter, + optsGetter OptsGetter, logger *slog.Logger, ) *Tracker { return &Tracker{ @@ -66,6 +73,7 @@ func NewTracker( store: store, preconfContract: preconfContract, receiptGetter: receiptGetter, + optsGetter: optsGetter, newL1Blocks: make(chan *blocktracker.BlocktrackerNewL1Block), enryptedCmts: make(chan *preconfcommstore.PreconfcommitmentstoreEncryptedCommitmentStored), commitments: make(chan *preconfcommstore.PreconfcommitmentstoreCommitmentStored), @@ -222,14 +230,29 @@ func (t *Tracker) handleNewL1Block( } startTime := time.Now() + var commitmentIdx [32]byte + copy(commitmentIdx[:], commitment.CommitmentIndex[:]) + + bidAmt, ok := new(big.Int).SetString(commitment.Bid.BidAmount, 10) + if !ok { + t.logger.Error("failed to parse bid amount", "bidAmount", commitment.Bid.BidAmount) + continue + } + + opts, err := t.optsGetter(ctx) + if err != nil { + t.logger.Error("failed to get transact opts", "error", err) + continue + } + txHash, err := t.preconfContract.OpenCommitment( - ctx, - commitment.EncryptedPreConfirmation.CommitmentIndex, - commitment.PreConfirmation.Bid.BidAmount, - commitment.PreConfirmation.Bid.BlockNumber, + opts, + commitmentIdx, + bidAmt.Uint64(), + uint64(commitment.PreConfirmation.Bid.BlockNumber), commitment.PreConfirmation.Bid.TxHash, - commitment.PreConfirmation.Bid.DecayStartTimestamp, - commitment.PreConfirmation.Bid.DecayEndTimestamp, + uint64(commitment.PreConfirmation.Bid.DecayStartTimestamp), + uint64(commitment.PreConfirmation.Bid.DecayEndTimestamp), commitment.PreConfirmation.Bid.Signature, commitment.PreConfirmation.Signature, commitment.PreConfirmation.SharedSecret, diff --git a/p2p/pkg/preconfirmation/tracker/tracker_test.go b/p2p/pkg/preconfirmation/tracker/tracker_test.go index 9bcaaf4c0..4060b731f 100644 --- a/p2p/pkg/preconfirmation/tracker/tracker_test.go +++ b/p2p/pkg/preconfirmation/tracker/tracker_test.go @@ -13,6 +13,7 @@ import ( "testing" "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" blocktracker "github.com/primev/mev-commit/contracts-abi/clients/BlockTracker" @@ -57,6 +58,11 @@ func TestTracker(t *testing.T) { st, contract, &testReceiptGetter{count: 1}, + func(context.Context) (*bind.TransactOpts, error) { + return &bind.TransactOpts{ + From: common.HexToAddress("0x1234"), + }, nil + }, util.NewTestLogger(io.Discard), ) @@ -172,30 +178,30 @@ func TestTracker(t *testing.T) { for _, c := range opened { oc := <-contract.openedCommitments - if !bytes.Equal(c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex) { + if !bytes.Equal(c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex[:]) { t.Fatalf( "expected commitment index %x, got %x", c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex, ) } - if c.PreConfirmation.Bid.BidAmount != oc.bid { - t.Fatalf("expected bid %s, got %s", c.PreConfirmation.Bid.BidAmount, oc.bid) + if c.PreConfirmation.Bid.BidAmount != strconv.Itoa(int(oc.bid)) { + t.Fatalf("expected bid %s, got %d", c.PreConfirmation.Bid.BidAmount, oc.bid) } - if c.PreConfirmation.Bid.BlockNumber != oc.blockNumber { + if c.PreConfirmation.Bid.BlockNumber != int64(oc.blockNumber) { t.Fatalf("expected block number %d, got %d", c.PreConfirmation.Bid.BlockNumber, oc.blockNumber) } if c.PreConfirmation.Bid.TxHash != oc.txnHash { t.Fatalf("expected txn hash %s, got %s", c.PreConfirmation.Bid.TxHash, oc.txnHash) } - if c.PreConfirmation.Bid.DecayStartTimestamp != oc.decayStartTimeStamp { + if c.PreConfirmation.Bid.DecayStartTimestamp != int64(oc.decayStartTimeStamp) { t.Fatalf( "expected decay start timestamp %d, got %d", c.PreConfirmation.Bid.DecayStartTimestamp, oc.decayStartTimeStamp, ) } - if c.PreConfirmation.Bid.DecayEndTimestamp != oc.decayEndTimeStamp { + if c.PreConfirmation.Bid.DecayEndTimestamp != int64(oc.decayEndTimeStamp) { t.Fatalf("expected decay end timestamp %d, got %d", c.PreConfirmation.Bid.DecayEndTimestamp, oc.decayEndTimeStamp) } if !bytes.Equal(c.PreConfirmation.Bid.Signature, oc.bidSignature) { @@ -240,30 +246,30 @@ func TestTracker(t *testing.T) { for _, c := range opened { oc := <-contract.openedCommitments - if !bytes.Equal(c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex) { + if !bytes.Equal(c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex[:]) { t.Fatalf( "expected commitment index %x, got %x", c.EncryptedPreConfirmation.CommitmentIndex, oc.encryptedCommitmentIndex, ) } - if c.PreConfirmation.Bid.BidAmount != oc.bid { - t.Fatalf("expected bid %s, got %s", c.PreConfirmation.Bid.BidAmount, oc.bid) + if c.PreConfirmation.Bid.BidAmount != strconv.Itoa(int(oc.bid)) { + t.Fatalf("expected bid %s, got %d", c.PreConfirmation.Bid.BidAmount, oc.bid) } - if c.PreConfirmation.Bid.BlockNumber != oc.blockNumber { + if c.PreConfirmation.Bid.BlockNumber != int64(oc.blockNumber) { t.Fatalf("expected block number %d, got %d", c.PreConfirmation.Bid.BlockNumber, oc.blockNumber) } if c.PreConfirmation.Bid.TxHash != oc.txnHash { t.Fatalf("expected txn hash %s, got %s", c.PreConfirmation.Bid.TxHash, oc.txnHash) } - if c.PreConfirmation.Bid.DecayStartTimestamp != oc.decayStartTimeStamp { + if c.PreConfirmation.Bid.DecayStartTimestamp != int64(oc.decayStartTimeStamp) { t.Fatalf( "expected decay start timestamp %d, got %d", c.PreConfirmation.Bid.DecayStartTimestamp, oc.decayStartTimeStamp, ) } - if c.PreConfirmation.Bid.DecayEndTimestamp != oc.decayEndTimeStamp { + if c.PreConfirmation.Bid.DecayEndTimestamp != int64(oc.decayEndTimeStamp) { t.Fatalf("expected decay end timestamp %d, got %d", c.PreConfirmation.Bid.DecayEndTimestamp, oc.decayEndTimeStamp) } if !bytes.Equal(c.PreConfirmation.Bid.Signature, oc.bidSignature) { @@ -295,12 +301,12 @@ func TestTracker(t *testing.T) { } type openedCommitment struct { - encryptedCommitmentIndex []byte - bid string - blockNumber int64 + encryptedCommitmentIndex [32]byte + bid uint64 + blockNumber uint64 txnHash string - decayStartTimeStamp int64 - decayEndTimeStamp int64 + decayStartTimeStamp uint64 + decayEndTimeStamp uint64 bidSignature []byte commitmentSignature []byte sharedSecretKey []byte @@ -311,17 +317,17 @@ type testPreconfContract struct { } func (t *testPreconfContract) OpenCommitment( - ctx context.Context, - encryptedCommitmentIndex []byte, - bid string, - blockNumber int64, + _ *bind.TransactOpts, + encryptedCommitmentIndex [32]byte, + bid uint64, + blockNumber uint64, txnHash string, - decayStartTimeStamp int64, - decayEndTimeStamp int64, + decayStartTimeStamp uint64, + decayEndTimeStamp uint64, bidSignature []byte, commitmentSignature []byte, sharedSecretKey []byte, -) (common.Hash, error) { +) (*types.Transaction, error) { t.openedCommitments <- openedCommitment{ encryptedCommitmentIndex: encryptedCommitmentIndex, bid: bid, @@ -333,7 +339,7 @@ func (t *testPreconfContract) OpenCommitment( commitmentSignature: commitmentSignature, sharedSecretKey: sharedSecretKey, } - return common.Hash{}, nil + return types.NewTransaction(0, common.Address{}, nil, 0, nil, nil), nil } type testReceiptGetter struct { diff --git a/p2p/pkg/rpc/bidder/service.go b/p2p/pkg/rpc/bidder/service.go index 95d097fdb..caaec8a09 100644 --- a/p2p/pkg/rpc/bidder/service.go +++ b/p2p/pkg/rpc/bidder/service.go @@ -10,10 +10,12 @@ import ( "time" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" bidderapiv1 "github.com/primev/mev-commit/p2p/gen/go/bidderapi/v1" preconfirmationv1 "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" - registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/bidder_registry" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/wrapperspb" @@ -21,28 +23,34 @@ import ( type Service struct { bidderapiv1.UnimplementedBidderServer - sender PreconfSender owner common.Address - registryContract registrycontract.Interface + sender PreconfSender + registryContract BidderRegistryContract blockTrackerContract BlockTrackerContract + watcher TxWatcher + optsGetter OptsGetter logger *slog.Logger metrics *metrics validator *protovalidate.Validator } func NewService( - sender PreconfSender, owner common.Address, - registryContract registrycontract.Interface, + sender PreconfSender, + registryContract BidderRegistryContract, blockTrackerContract BlockTrackerContract, validator *protovalidate.Validator, + watcher TxWatcher, + optsGetter OptsGetter, logger *slog.Logger, ) *Service { return &Service{ - sender: sender, owner: owner, + sender: sender, registryContract: registryContract, blockTrackerContract: blockTrackerContract, + watcher: watcher, + optsGetter: optsGetter, logger: logger, metrics: newMetrics(), validator: validator, @@ -53,11 +61,26 @@ type PreconfSender interface { SendBid(context.Context, string, string, int64, int64, int64) (chan *preconfirmationv1.PreConfirmation, error) } +type BidderRegistryContract interface { + DepositForSpecificWindow(*bind.TransactOpts, *big.Int) (*types.Transaction, error) + WithdrawBidderAmountFromWindow(*bind.TransactOpts, common.Address, *big.Int) (*types.Transaction, error) + GetDeposit(*bind.CallOpts, common.Address, *big.Int) (*big.Int, error) + MinDeposit(*bind.CallOpts) (*big.Int, error) + ParseBidderRegistered(types.Log) (*bidderregistry.BidderregistryBidderRegistered, error) + ParseBidderWithdrawal(types.Log) (*bidderregistry.BidderregistryBidderWithdrawal, error) +} + type BlockTrackerContract interface { GetCurrentWindow() (*big.Int, error) GetBlocksPerWindow() (*big.Int, error) } +type TxWatcher interface { + WaitForReceipt(context.Context, *types.Transaction) (*types.Receipt, error) +} + +type OptsGetter func(context.Context) (*bind.TransactOpts, error) + func (s *Service) SendBid( bid *bidderapiv1.Bid, srv bidderapiv1.Bidder_SendBidServer, @@ -137,22 +160,44 @@ func (s *Service) Deposit( return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", r.Amount) } - err = s.registryContract.DepositForSpecificWindow(ctx, amount, windowToDeposit) + opts, err := s.optsGetter(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting transact opts: %v", err) + } + opts.Value = amount + + tx, err := s.registryContract.DepositForSpecificWindow(opts, windowToDeposit) if err != nil { return nil, status.Errorf(codes.Internal, "deposit: %v", err) } - stakeAmount, err := s.registryContract.GetDeposit(ctx, s.owner, windowToDeposit) + receipt, err := s.watcher.WaitForReceipt(ctx, tx) if err != nil { - return nil, status.Errorf(codes.Internal, "getting deposit: %v", err) + return nil, status.Errorf(codes.Internal, "waiting for receipt: %v", err) } - s.logger.Info("deposit successful", "amount", stakeAmount.String(), "window", windowToDeposit) + if receipt.Status != types.ReceiptStatusSuccessful { + return nil, status.Errorf(codes.Internal, "receipt status: %v", receipt.Status) + } - return &bidderapiv1.DepositResponse{ - Amount: stakeAmount.String(), - WindowNumber: wrapperspb.UInt64(windowToDeposit.Uint64()), - }, nil + for _, log := range receipt.Logs { + if registration, err := s.registryContract.ParseBidderRegistered(*log); err == nil { + s.logger.Info("deposit successful", "amount", registration.DepositedAmount, "window", registration.WindowNumber) + return &bidderapiv1.DepositResponse{ + Amount: registration.DepositedAmount.String(), + WindowNumber: wrapperspb.UInt64(registration.WindowNumber.Uint64()), + }, nil + } + } + + s.logger.Error( + "deposit successful but missing log", + "txHash", receipt.TxHash.Hex(), + "window", windowToDeposit, + "logs", receipt.Logs, + ) + + return nil, status.Errorf(codes.Internal, "missing log for deposit") } func (s *Service) calculateWindowToDeposit(ctx context.Context, r *bidderapiv1.DepositRequest, currentWindow uint64) (*big.Int, error) { @@ -190,7 +235,10 @@ func (s *Service) GetDeposit( } else { window = new(big.Int).SetUint64(r.WindowNumber.Value) } - stakeAmount, err := s.registryContract.GetDeposit(ctx, s.owner, window) + stakeAmount, err := s.registryContract.GetDeposit(&bind.CallOpts{ + From: s.owner, + Context: ctx, + }, s.owner, window) if err != nil { return nil, status.Errorf(codes.Internal, "getting deposit: %v", err) } @@ -202,7 +250,10 @@ func (s *Service) GetMinDeposit( ctx context.Context, _ *bidderapiv1.EmptyMessage, ) (*bidderapiv1.DepositResponse, error) { - stakeAmount, err := s.registryContract.GetMinDeposit(ctx) + stakeAmount, err := s.registryContract.MinDeposit(&bind.CallOpts{ + From: s.owner, + Context: ctx, + }) if err != nil { return nil, status.Errorf(codes.Internal, "getting min deposit: %v", err) } @@ -230,15 +281,41 @@ func (s *Service) Withdraw( window = new(big.Int).SetUint64(r.WindowNumber.Value) } - amount, err := s.registryContract.WithdrawDeposit(ctx, window) + opts, err := s.optsGetter(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting transact opts: %v", err) + } + + tx, err := s.registryContract.WithdrawBidderAmountFromWindow(opts, s.owner, window) if err != nil { return nil, status.Errorf(codes.Internal, "withdrawing deposit: %v", err) } - s.logger.Info("withdraw successful", "amount", amount.String(), "window", window) + receipt, err := s.watcher.WaitForReceipt(ctx, tx) + if err != nil { + return nil, status.Errorf(codes.Internal, "waiting for receipt: %v", err) + } + + if receipt.Status != types.ReceiptStatusSuccessful { + return nil, status.Errorf(codes.Internal, "receipt status: %v", receipt.Status) + } + + for _, log := range receipt.Logs { + if withdrawal, err := s.registryContract.ParseBidderWithdrawal(*log); err == nil { + s.logger.Info("withdrawal successful", "amount", withdrawal.Amount.String(), "window", withdrawal.Window.String()) + return &bidderapiv1.WithdrawResponse{ + Amount: withdrawal.Amount.String(), + WindowNumber: wrapperspb.UInt64(withdrawal.Window.Uint64()), + }, nil + } + } + + s.logger.Error( + "withdraw successful but missing log", + "txHash", receipt.TxHash.Hex(), + "window", window.Uint64(), + "logs", receipt.Logs, + ) - return &bidderapiv1.WithdrawResponse{ - Amount: amount.String(), - WindowNumber: wrapperspb.UInt64(window.Uint64()), - }, nil + return nil, status.Errorf(codes.Internal, "missing log for withdrawal") } diff --git a/p2p/pkg/rpc/bidder/service_test.go b/p2p/pkg/rpc/bidder/service_test.go index 031a1f958..3a15f6f05 100644 --- a/p2p/pkg/rpc/bidder/service_test.go +++ b/p2p/pkg/rpc/bidder/service_test.go @@ -12,7 +12,10 @@ import ( "testing" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + bidderregistry "github.com/primev/mev-commit/contracts-abi/clients/BidderRegistry" bidderapiv1 "github.com/primev/mev-commit/p2p/gen/go/bidderapi/v1" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" bidderapi "github.com/primev/mev-commit/p2p/pkg/rpc/bidder" @@ -80,25 +83,60 @@ type testRegistryContract struct { minDeposit *big.Int } -func (t *testRegistryContract) DepositForSpecificWindow(ctx context.Context, amount, window *big.Int) error { - t.deposit = amount - return nil +func (t *testRegistryContract) DepositForSpecificWindow(opts *bind.TransactOpts, _ *big.Int) (*types.Transaction, error) { + t.deposit = opts.Value + return types.NewTransaction(1, common.Address{}, nil, 0, nil, nil), nil } -func (t *testRegistryContract) GetDeposit(ctx context.Context, address common.Address, window *big.Int) (*big.Int, error) { +func (t *testRegistryContract) WithdrawBidderAmountFromWindow( + opts *bind.TransactOpts, + address common.Address, + window *big.Int, +) (*types.Transaction, error) { + return types.NewTransaction(2, common.Address{}, nil, 0, nil, nil), nil +} + +func (t *testRegistryContract) GetDeposit(_ *bind.CallOpts, _ common.Address, _ *big.Int) (*big.Int, error) { return t.deposit, nil } -func (t *testRegistryContract) GetMinDeposit(ctx context.Context) (*big.Int, error) { +func (t *testRegistryContract) MinDeposit(_ *bind.CallOpts) (*big.Int, error) { return t.minDeposit, nil } -func (t *testRegistryContract) CheckBidderDeposit(ctx context.Context, address common.Address, window, numberOfRounds *big.Int) bool { - return t.deposit.Cmp(t.minDeposit) > 0 +func (t *testRegistryContract) ParseBidderRegistered(_ types.Log) (*bidderregistry.BidderregistryBidderRegistered, error) { + return &bidderregistry.BidderregistryBidderRegistered{ + DepositedAmount: t.deposit, + WindowNumber: big.NewInt(1), + }, nil } -func (t *testRegistryContract) WithdrawDeposit(ctx context.Context, window *big.Int) (*big.Int, error) { - return t.deposit, nil +func (t *testRegistryContract) ParseBidderWithdrawal(_ types.Log) (*bidderregistry.BidderregistryBidderWithdrawal, error) { + return &bidderregistry.BidderregistryBidderWithdrawal{ + Amount: t.deposit, + Window: big.NewInt(1), + }, nil +} + +type testTxWatcher struct { + nonce int +} + +func (t *testTxWatcher) WaitForReceipt(_ context.Context, tx *types.Transaction) (*types.Receipt, error) { + t.nonce++ + if tx.Nonce() != uint64(t.nonce) { + return nil, errors.New("nonce mismatch") + } + return &types.Receipt{ + Status: 1, + Logs: []*types.Log{ + { + Address: common.Address{}, + Topics: []common.Hash{}, + Data: []byte{}, + }, + }, + }, nil } type testBlockTrackerContract struct { @@ -129,11 +167,18 @@ func startServer(t *testing.T) bidderapiv1.BidderClient { sender := &testSender{noOfPreconfs: 2} blockTrackerContract := &testBlockTrackerContract{blocksPerWindow: 64, blockNumberToWinner: make(map[uint64]common.Address)} srvImpl := bidderapi.NewService( - sender, owner, + sender, registryContract, blockTrackerContract, validator, + &testTxWatcher{}, + func(ctx context.Context) (*bind.TransactOpts, error) { + return &bind.TransactOpts{ + From: owner, + Context: ctx, + }, nil + }, logger, ) diff --git a/p2p/pkg/rpc/debug/service.go b/p2p/pkg/rpc/debug/service.go new file mode 100644 index 000000000..8d70808d1 --- /dev/null +++ b/p2p/pkg/rpc/debug/service.go @@ -0,0 +1,138 @@ +package debugapi + +import ( + "context" + "time" + + "github.com/ethereum/go-ethereum/common" + debugapiv1 "github.com/primev/mev-commit/p2p/gen/go/debugapi/v1" + "github.com/primev/mev-commit/p2p/pkg/p2p" + "github.com/primev/mev-commit/p2p/pkg/store" + "github.com/primev/mev-commit/p2p/pkg/topology" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" + "google.golang.org/protobuf/types/known/structpb" +) + +type Service struct { + debugapiv1.UnimplementedDebugServiceServer + store Store + canceller Canceller + p2p P2PService + topology Topology +} + +func NewService( + store Store, + canceller Canceller, + p2p P2PService, + topology Topology, +) *Service { + return &Service{ + store: store, + canceller: canceller, + p2p: p2p, + topology: topology, + } +} + +type Store interface { + PendingTxns() ([]*store.TxnDetails, error) +} + +type Canceller interface { + CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) +} + +type P2PService interface { + Self() map[string]interface{} + BlockedPeers() []p2p.BlockedPeerInfo +} + +type Topology interface { + GetPeers(q topology.Query) []p2p.Peer +} + +func (s *Service) GetTopology( + ctx context.Context, + _ *debugapiv1.EmptyMessage, +) (*debugapiv1.TopologyResponse, error) { + providers := s.topology.GetPeers(topology.Query{Type: p2p.PeerTypeProvider}) + bidders := s.topology.GetPeers(topology.Query{Type: p2p.PeerTypeBidder}) + self := s.p2p.Self() + blocked := s.p2p.BlockedPeers() + + resp := make(map[string]interface{}) + + if len(providers) > 0 { + connectedProviders := make([]interface{}, len(providers)) + for i, p := range providers { + connectedProviders[i] = p.EthAddress.String() + } + resp["connected_providers"] = connectedProviders + } + + if len(bidders) > 0 { + connectedBidders := make([]interface{}, len(bidders)) + for i, b := range bidders { + connectedBidders[i] = b.EthAddress.String() + } + resp["connected_bidders"] = connectedBidders + } + + if len(self) > 0 { + resp["self"] = self + } + + if len(blocked) > 0 { + blockedPeers := make([]interface{}, len(blocked)) + for i, b := range blocked { + blockedPeers[i] = map[string]interface{}{ + "peer": b.Peer.String(), + "reason": b.Reason, + } + } + resp["blocked_peers"] = blockedPeers + } + + structResp, err := structpb.NewStruct(resp) + if err != nil { + return nil, status.Errorf(codes.Internal, "creating response: %v", err) + } + + return &debugapiv1.TopologyResponse{Topology: structResp}, nil +} + +func (s *Service) GetPendingTransactions( + ctx context.Context, + _ *debugapiv1.EmptyMessage, +) (*debugapiv1.PendingTransactionsResponse, error) { + txns, err := s.store.PendingTxns() + if err != nil { + return nil, status.Errorf(codes.Internal, "getting pending transactions: %v", err) + } + + txnsMsg := make([]*debugapiv1.TransactionInfo, len(txns)) + for i, txn := range txns { + txnsMsg[i] = &debugapiv1.TransactionInfo{ + TxHash: txn.Hash.Hex(), + Nonce: int64(txn.Nonce), + Created: time.Unix(txn.Created, 0).String(), + } + } + + return &debugapiv1.PendingTransactionsResponse{PendingTransactions: txnsMsg}, nil +} + +func (s *Service) CancelTransaction( + ctx context.Context, + cancel *debugapiv1.CancelTransactionReq, +) (*debugapiv1.CancelTransactionResponse, error) { + txHash := common.HexToHash(cancel.TxHash) + cHash, err := s.canceller.CancelTx(ctx, txHash) + if err != nil { + return nil, status.Errorf(codes.Internal, "cancelling transaction: %v", err) + } + + return &debugapiv1.CancelTransactionResponse{TxHash: cHash.Hex()}, nil +} diff --git a/p2p/pkg/rpc/debug/service_test.go b/p2p/pkg/rpc/debug/service_test.go new file mode 100644 index 000000000..c48a40663 --- /dev/null +++ b/p2p/pkg/rpc/debug/service_test.go @@ -0,0 +1,162 @@ +package debugapi_test + +import ( + "context" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + debugapiv1 "github.com/primev/mev-commit/p2p/gen/go/debugapi/v1" + "github.com/primev/mev-commit/p2p/pkg/p2p" + debugapi "github.com/primev/mev-commit/p2p/pkg/rpc/debug" + "github.com/primev/mev-commit/p2p/pkg/store" + "github.com/primev/mev-commit/p2p/pkg/topology" + "github.com/stretchr/testify/assert" +) + +type mockStore struct{} + +func (m *mockStore) PendingTxns() ([]*store.TxnDetails, error) { + return []*store.TxnDetails{ + { + Hash: common.HexToHash("0x00001"), + Nonce: 1, + Created: time.Now().Unix(), + }, + { + Hash: common.HexToHash("0x00002"), + Nonce: 2, + Created: time.Now().Unix(), + }, + }, nil +} + +type mockCanceller struct{} + +func (m *mockCanceller) CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) { + return txHash, nil +} + +type mockP2PService struct{} + +func (m *mockP2PService) Self() map[string]interface{} { + return map[string]interface{}{ + "self_key": "self_value", + } +} + +func (m *mockP2PService) BlockedPeers() []p2p.BlockedPeerInfo { + return []p2p.BlockedPeerInfo{ + { + Peer: common.HexToAddress("0xab"), + Reason: "reason1", + }, + { + Peer: common.HexToAddress("0xcd"), + Reason: "reason2", + }, + } +} + +type mockTopology struct{} + +func (m *mockTopology) GetPeers(q topology.Query) []p2p.Peer { + if q.Type == p2p.PeerTypeProvider { + return []p2p.Peer{ + { + EthAddress: common.HexToAddress("0x11111"), + }, + { + EthAddress: common.HexToAddress("0x22222"), + }, + } + } else if q.Type == p2p.PeerTypeBidder { + return []p2p.Peer{ + { + EthAddress: common.HexToAddress("0x33333"), + }, + { + EthAddress: common.HexToAddress("0x44444"), + }, + } + } + return nil +} + +func TestService_GetTopology(t *testing.T) { + service := debugapi.NewService(&mockStore{}, &mockCanceller{}, &mockP2PService{}, &mockTopology{}) + + ctx := context.Background() + req := &debugapiv1.EmptyMessage{} + + resp, err := service.GetTopology(ctx, req) + + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.NotNil(t, resp.Topology) + + self, ok := resp.Topology.Fields["self"] + assert.True(t, ok) + assert.Equal(t, 1, len(self.GetStructValue().Fields)) + assert.Equal(t, "self_value", self.GetStructValue().Fields["self_key"].GetStringValue()) + + connectedProviders, ok := resp.Topology.Fields["connected_providers"] + assert.True(t, ok) + assert.Equal(t, 2, len(connectedProviders.GetListValue().Values)) + assert.Equal(t, common.HexToAddress("0x11111").String(), connectedProviders.GetListValue().Values[0].GetStringValue()) + assert.Equal(t, common.HexToAddress("0x22222").String(), connectedProviders.GetListValue().Values[1].GetStringValue()) + + connectedBidders, ok := resp.Topology.Fields["connected_bidders"] + assert.True(t, ok) + assert.Equal(t, 2, len(connectedBidders.GetListValue().Values)) + assert.Equal(t, common.HexToAddress("0x33333").String(), connectedBidders.GetListValue().Values[0].GetStringValue()) + assert.Equal(t, common.HexToAddress("0x44444").String(), connectedBidders.GetListValue().Values[1].GetStringValue()) + + blockedPeers, ok := resp.Topology.Fields["blocked_peers"] + assert.True(t, ok) + assert.Equal(t, 2, len(blockedPeers.GetListValue().Values)) + for _, v := range blockedPeers.GetListValue().Values { + assert.Equal(t, 2, len(v.GetStructValue().Fields)) + if v.GetStructValue().Fields["peer"].GetStringValue() == common.HexToAddress("0xab").String() { + assert.Equal(t, "reason1", v.GetStructValue().Fields["reason"].GetStringValue()) + } else if v.GetStructValue().Fields["peer"].GetStringValue() == common.HexToAddress("0xcd").String() { + assert.Equal(t, "reason2", v.GetStructValue().Fields["reason"].GetStringValue()) + } else { + assert.Fail(t, "unexpected peer") + } + } +} + +func TestService_GetPendingTransactions(t *testing.T) { + service := debugapi.NewService(&mockStore{}, &mockCanceller{}, &mockP2PService{}, &mockTopology{}) + + ctx := context.Background() + req := &debugapiv1.EmptyMessage{} + + resp, err := service.GetPendingTransactions(ctx, req) + + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Equal(t, 2, len(resp.PendingTransactions)) + assert.Equal(t, common.HexToHash("0x00001").String(), resp.PendingTransactions[0].TxHash) + assert.Equal(t, int64(1), resp.PendingTransactions[0].Nonce) + assert.NotEmpty(t, resp.PendingTransactions[0].Created) + assert.Equal(t, common.HexToHash("0x00002").String(), resp.PendingTransactions[1].TxHash) + assert.Equal(t, int64(2), resp.PendingTransactions[1].Nonce) + assert.NotEmpty(t, resp.PendingTransactions[1].Created) +} + +func TestService_CancelTransaction(t *testing.T) { + service := debugapi.NewService(&mockStore{}, &mockCanceller{}, &mockP2PService{}, &mockTopology{}) + + ctx := context.Background() + req := &debugapiv1.CancelTransactionReq{ + TxHash: common.HexToHash("0x12345").String(), + } + + resp, err := service.CancelTransaction(ctx, req) + + assert.NoError(t, err) + assert.NotNil(t, resp) + assert.Equal(t, common.HexToHash("0x12345").String(), resp.TxHash) +} diff --git a/p2p/pkg/rpc/provider/service.go b/p2p/pkg/rpc/provider/service.go index f9899d46d..e4c344a83 100644 --- a/p2p/pkg/rpc/provider/service.go +++ b/p2p/pkg/rpc/provider/service.go @@ -11,11 +11,12 @@ import ( "sync" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" - registrycontract "github.com/primev/mev-commit/p2p/pkg/contracts/provider_registry" - "github.com/primev/mev-commit/p2p/pkg/evmclient" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -32,22 +33,32 @@ type Service struct { bidsMu sync.Mutex logger *slog.Logger owner common.Address - registryContract registrycontract.Interface - evmClient EvmClient + registryContract ProviderRegistryContract + watcher Watcher + optsGetter OptsGetter metrics *metrics validator *protovalidate.Validator } -type EvmClient interface { - PendingTxns() []evmclient.TxnInfo - CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) +type ProviderRegistryContract interface { + RegisterAndStake(*bind.TransactOpts) (*types.Transaction, error) + CheckStake(*bind.CallOpts, common.Address) (*big.Int, error) + MinStake(*bind.CallOpts) (*big.Int, error) + ParseFundsDeposited(types.Log) (*providerregistry.ProviderregistryFundsDeposited, error) } +type Watcher interface { + WaitForReceipt(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) +} + +type OptsGetter func(ctx context.Context) (*bind.TransactOpts, error) + func NewService( logger *slog.Logger, - registryContract registrycontract.Interface, + registryContract ProviderRegistryContract, owner common.Address, - e EvmClient, + watcher Watcher, + optsGetter OptsGetter, validator *protovalidate.Validator, ) *Service { return &Service{ @@ -56,7 +67,8 @@ func NewService( registryContract: registryContract, owner: owner, logger: logger, - evmClient: e, + watcher: watcher, + optsGetter: optsGetter, metrics: newMetrics(), validator: validator, } @@ -187,24 +199,45 @@ func (s *Service) RegisterStake( return nil, status.Errorf(codes.InvalidArgument, "parsing amount: %v", stake.Amount) } - err = s.registryContract.RegisterProvider(ctx, amount) + opts, err := s.optsGetter(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "getting transact opts: %v", err) + } + opts.Value = amount + + tx, err := s.registryContract.RegisterAndStake(opts) if err != nil { return nil, status.Errorf(codes.Internal, "registering stake: %v", err) } - stakeAmount, err := s.registryContract.GetStake(ctx, s.owner) + receipt, err := s.watcher.WaitForReceipt(ctx, tx) if err != nil { - return nil, status.Errorf(codes.Internal, "getting stake: %v", err) + return nil, status.Errorf(codes.Internal, "waiting for receipt: %v", err) } - return &providerapiv1.StakeResponse{Amount: stakeAmount.String()}, nil + if receipt.Status != types.ReceiptStatusSuccessful { + return nil, status.Errorf(codes.Internal, "receipt status: %v", receipt.Status) + } + + for _, log := range receipt.Logs { + if registration, err := s.registryContract.ParseFundsDeposited(*log); err == nil { + s.logger.Info("stake registered", "amount", registration.Amount) + return &providerapiv1.StakeResponse{Amount: registration.Amount.String()}, nil + } + } + + s.logger.Error("no registration event found") + return nil, status.Error(codes.Internal, "no registration event found") } func (s *Service) GetStake( ctx context.Context, _ *providerapiv1.EmptyMessage, ) (*providerapiv1.StakeResponse, error) { - stakeAmount, err := s.registryContract.GetStake(ctx, s.owner) + stakeAmount, err := s.registryContract.CheckStake(&bind.CallOpts{ + Context: ctx, + From: s.owner, + }, s.owner) if err != nil { return nil, status.Errorf(codes.Internal, "getting stake: %v", err) } @@ -216,41 +249,13 @@ func (s *Service) GetMinStake( ctx context.Context, _ *providerapiv1.EmptyMessage, ) (*providerapiv1.StakeResponse, error) { - stakeAmount, err := s.registryContract.GetMinStake(ctx) + stakeAmount, err := s.registryContract.MinStake(&bind.CallOpts{ + Context: ctx, + From: s.owner, + }) if err != nil { return nil, status.Errorf(codes.Internal, "getting min stake: %v", err) } return &providerapiv1.StakeResponse{Amount: stakeAmount.String()}, nil } - -func (s *Service) GetPendingTxns( - ctx context.Context, - _ *providerapiv1.EmptyMessage, -) (*providerapiv1.PendingTxnsResponse, error) { - txns := s.evmClient.PendingTxns() - - txnsMsg := make([]*providerapiv1.TransactionInfo, len(txns)) - for i, txn := range txns { - txnsMsg[i] = &providerapiv1.TransactionInfo{ - TxHash: txn.Hash, - Nonce: int64(txn.Nonce), - Created: txn.Created, - } - } - - return &providerapiv1.PendingTxnsResponse{PendingTxns: txnsMsg}, nil -} - -func (s *Service) CancelTransaction( - ctx context.Context, - cancel *providerapiv1.CancelReq, -) (*providerapiv1.CancelResponse, error) { - txHash := common.HexToHash(cancel.TxHash) - cHash, err := s.evmClient.CancelTx(ctx, txHash) - if err != nil { - return nil, status.Errorf(codes.Internal, "cancelling transaction: %v", err) - } - - return &providerapiv1.CancelResponse{TxHash: cHash.Hex()}, nil -} diff --git a/p2p/pkg/rpc/provider/service_test.go b/p2p/pkg/rpc/provider/service_test.go index bacee0a61..956b07d5a 100644 --- a/p2p/pkg/rpc/provider/service_test.go +++ b/p2p/pkg/rpc/provider/service_test.go @@ -10,10 +10,12 @@ import ( "time" "github.com/bufbuild/protovalidate-go" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + providerregistry "github.com/primev/mev-commit/contracts-abi/clients/ProviderRegistry" preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" providerapiv1 "github.com/primev/mev-commit/p2p/gen/go/providerapi/v1" - "github.com/primev/mev-commit/p2p/pkg/evmclient" providerapi "github.com/primev/mev-commit/p2p/pkg/rpc/provider" "github.com/primev/mev-commit/x/util" "google.golang.org/grpc" @@ -26,38 +28,42 @@ type testRegistryContract struct { minStake *big.Int } -func (t *testRegistryContract) RegisterProvider(ctx context.Context, amount *big.Int) error { - t.stake = amount - return nil +func (t *testRegistryContract) RegisterAndStake(opts *bind.TransactOpts) (*types.Transaction, error) { + t.stake = opts.Value + return types.NewTransaction(1, common.Address{}, nil, 0, nil, nil), nil } -func (t *testRegistryContract) GetStake(ctx context.Context, address common.Address) (*big.Int, error) { +func (t *testRegistryContract) CheckStake(_ *bind.CallOpts, address common.Address) (*big.Int, error) { return t.stake, nil } -func (t *testRegistryContract) GetMinStake(ctx context.Context) (*big.Int, error) { +func (t *testRegistryContract) MinStake(_ *bind.CallOpts) (*big.Int, error) { return t.minStake, nil } -func (t *testRegistryContract) CheckProviderRegistered(ctx context.Context, address common.Address) bool { - return t.stake.Cmp(t.minStake) > 0 +func (t *testRegistryContract) ParseFundsDeposited(log types.Log) (*providerregistry.ProviderregistryFundsDeposited, error) { + return &providerregistry.ProviderregistryFundsDeposited{ + Provider: common.Address{}, + Amount: t.stake, + }, nil } -type testEVMClient struct { - pendingTxns []evmclient.TxnInfo - cancelledHashes []common.Hash -} - -func (t *testEVMClient) PendingTxns() []evmclient.TxnInfo { - return t.pendingTxns -} +type testWatcher struct{} -func (t *testEVMClient) CancelTx(ctx context.Context, txHash common.Hash) (common.Hash, error) { - t.cancelledHashes = append(t.cancelledHashes, txHash) - return txHash, nil +func (t *testWatcher) WaitForReceipt(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) { + return &types.Receipt{ + Status: 1, + Logs: []*types.Log{ + { + Address: common.Address{}, + Topics: []common.Hash{}, + Data: []byte{}, + }, + }, + }, nil } -func startServer(t *testing.T, evm *testEVMClient) (providerapiv1.ProviderClient, *providerapi.Service) { +func startServer(t *testing.T) (providerapiv1.ProviderClient, *providerapi.Service) { buffer := 101024 * 1024 lis := bufconn.Listen(buffer) @@ -69,15 +75,18 @@ func startServer(t *testing.T, evm *testEVMClient) (providerapiv1.ProviderClient owner := common.HexToAddress("0x00001") registryContract := &testRegistryContract{minStake: big.NewInt(100000000000000000)} - if evm == nil { - evm = &testEVMClient{} - } srvImpl := providerapi.NewService( logger, registryContract, owner, - evm, + &testWatcher{}, + func(context.Context) (*bind.TransactOpts, error) { + return &bind.TransactOpts{ + From: owner, + Context: context.Background(), + }, nil + }, validator, ) @@ -114,7 +123,7 @@ func startServer(t *testing.T, evm *testEVMClient) (providerapiv1.ProviderClient func TestStakeHandling(t *testing.T) { t.Parallel() - client, _ := startServer(t, nil) + client, _ := startServer(t) t.Run("register stake", func(t *testing.T) { type testCase struct { @@ -282,7 +291,7 @@ func TestBidHandling(t *testing.T) { }, } { t.Run(tc.name, func(t *testing.T) { - client, svc := startServer(t, nil) + client, svc := startServer(t) bidCh := make(chan *providerapiv1.Bid) @@ -365,63 +374,3 @@ func TestBidHandling(t *testing.T) { }) } } - -func TestCancelTx(t *testing.T) { - t.Parallel() - - evmClient := &testEVMClient{ - pendingTxns: []evmclient.TxnInfo{ - { - Hash: common.HexToHash("0x00001").Hex(), - Nonce: 1, - Created: time.Now().String(), - }, - { - Hash: common.HexToHash("0x00002").Hex(), - Nonce: 2, - Created: time.Now().String(), - }, - }, - } - client, _ := startServer(t, evmClient) - - t.Run("get pending txns", func(t *testing.T) { - pendingTxns, err := client.GetPendingTxns(context.Background(), &providerapiv1.EmptyMessage{}) - if err != nil { - t.Fatalf("error getting pending txns: %v", err) - } - - if len(pendingTxns.PendingTxns) != len(evmClient.pendingTxns) { - t.Fatalf("expected %v pending txns, got %v", len(evmClient.pendingTxns), len(pendingTxns.PendingTxns)) - } - - for i, pendingTxn := range pendingTxns.PendingTxns { - if pendingTxn.TxHash != evmClient.pendingTxns[i].Hash { - t.Fatalf("expected tx hash to be %v, got %v", evmClient.pendingTxns[i].Hash, pendingTxn.TxHash) - } - if uint64(pendingTxn.Nonce) != evmClient.pendingTxns[i].Nonce { - t.Fatalf("expected nonce to be %v, got %v", evmClient.pendingTxns[i].Nonce, pendingTxn.Nonce) - } - if pendingTxn.Created != evmClient.pendingTxns[i].Created { - t.Fatalf("expected created to be %v, got %v", evmClient.pendingTxns[i].Created, pendingTxn.Created) - } - } - }) - - t.Run("cancel tx", func(t *testing.T) { - txHash := common.HexToHash("0x00001") - cancelTxHash, err := client.CancelTransaction(context.Background(), &providerapiv1.CancelReq{TxHash: txHash.Hex()}) - if err != nil { - t.Fatalf("error cancelling tx: %v", err) - } - if cancelTxHash.TxHash != txHash.Hex() { - t.Fatalf("expected cancel tx hash to be %v, got %v", txHash.Hex(), cancelTxHash.TxHash) - } - if len(evmClient.cancelledHashes) != 1 { - t.Fatalf("expected 1 cancelled tx, got %v", len(evmClient.cancelledHashes)) - } - if evmClient.cancelledHashes[0] != txHash { - t.Fatalf("expected cancelled tx hash to be %v, got %v", txHash, evmClient.cancelledHashes[0]) - } - }) -} diff --git a/p2p/pkg/store/store.go b/p2p/pkg/store/store.go index e764bb360..1b368fbbe 100644 --- a/p2p/pkg/store/store.go +++ b/p2p/pkg/store/store.go @@ -2,11 +2,14 @@ package store import ( "bytes" + "context" "crypto/ecdh" "fmt" "math/big" + "slices" "strings" "sync" + "time" "github.com/armon/go-radix" "github.com/ethereum/go-ethereum/common" @@ -14,7 +17,7 @@ import ( preconfpb "github.com/primev/mev-commit/p2p/gen/go/preconfirmation/v1" ) -var ( +const ( commitmentNS = "cm/" balanceNS = "bbs/" aesKeysNS = "aes/" @@ -23,6 +26,11 @@ var ( eciesPrivateKeyNS = "ecies/" nikePrivateKeyNS = "nike/" + // txns related keys + txNS = "tx/" +) + +var ( commitmentKey = func(blockNum int64, index []byte) string { return fmt.Sprintf("%s%d/%s", commitmentNS, blockNum, string(index)) } @@ -43,6 +51,10 @@ var ( bidderAesKey = func(bidder common.Address) string { return fmt.Sprintf("%s%s", aesKeysNS, bidder) } + + txKey = func(txHash common.Hash) string { + return fmt.Sprintf("%s%s", txNS, txHash.Hex()) + } ) type Store struct { @@ -308,3 +320,57 @@ func (s *Store) Len() int { return s.Tree.Len() } + +// Following are the methods to save and update the transaction details in the store. +// The store is used to keep track of the transactions that are sent to the blockchain and +// have not yet received the transaction receipt. These are used by the debug service +// to show the pending transactions and cancel them if needed. The store hooks up +// to the txmonitor package which allows a component to get notified when the transaction +// is sent to the blockchain and when the transaction receipt is received. As of now, +// the store is in-memory and doesn't persist the transaction details, so the update +// method is used to remove the transaction from the store. This will no longer be seen +// in the pending transactions list. +type TxnDetails struct { + Hash common.Hash + Nonce uint64 + Created int64 +} + +// Save implements the txmonitor.Saver interface. It saves the transaction hash and nonce in the store once +// the transaction is sent to the blockchain. +func (s *Store) Save(ctx context.Context, txHash common.Hash, nonce uint64) error { + s.mu.Lock() + defer s.mu.Unlock() + + _, _ = s.Tree.Insert(txKey(txHash), &TxnDetails{Hash: txHash, Nonce: nonce, Created: time.Now().Unix()}) + return nil +} + +// Update implements the txmonitor.Saver interface. It is called to update the status of the +// transaction once the monitor receives the transaction receipt. For the in-memory store, +// we don't need to update the but rather remove the transaction from the store as we dont +// need to keep track of it anymore. Once we implement a persistent store, we will need to +// update the status of the transaction and keep it in the store for future reference. +func (s *Store) Update(ctx context.Context, txHash common.Hash, status string) error { + s.mu.Lock() + defer s.mu.Unlock() + + _, _ = s.Tree.Delete(txKey(txHash)) + return nil +} + +func (s *Store) PendingTxns() ([]*TxnDetails, error) { + s.mu.RLock() + defer s.mu.RUnlock() + + txns := make([]*TxnDetails, 0) + s.Tree.WalkPrefix(txNS, func(key string, value interface{}) bool { + txns = append(txns, value.(*TxnDetails)) + return false + }) + + slices.SortFunc(txns, func(a, b *TxnDetails) int { + return int(a.Created - b.Created) + }) + return txns, nil +} diff --git a/p2p/pkg/store/store_test.go b/p2p/pkg/store/store_test.go index b252615f2..1b00ebefd 100644 --- a/p2p/pkg/store/store_test.go +++ b/p2p/pkg/store/store_test.go @@ -2,6 +2,7 @@ package store_test import ( "bytes" + "context" "crypto/ecdh" "crypto/rand" "math/big" @@ -275,4 +276,47 @@ func TestStore(t *testing.T) { t.Fatalf("expected nil, got %x", retrievedKey.Bytes()) } }) + + t.Run("txns", func(t *testing.T) { + for i := 1; i <= 10; i++ { + txHash := common.BigToHash(big.NewInt(int64(i))) + err := st.Save(context.Background(), txHash, uint64(i)) + if err != nil { + t.Fatal(err) + } + } + + txns, err := st.PendingTxns() + if err != nil { + t.Fatal(err) + } + + if len(txns) != 10 { + t.Fatalf("expected 10, got %d", len(txns)) + } + + for i := 1; i <= 10; i++ { + txHash := common.BigToHash(big.NewInt(int64(i))) + if txns[i-1].Hash.Cmp(txHash) != 0 { + t.Fatalf("expected %s, got %s", txHash, txns[i-1].Hash) + } + } + + for i := 1; i <= 10; i++ { + txHash := common.BigToHash(big.NewInt(int64(i))) + err := st.Update(context.Background(), txHash, "status") + if err != nil { + t.Fatal(err) + } + } + + txns, err = st.PendingTxns() + if err != nil { + t.Fatal(err) + } + + if len(txns) != 0 { + t.Fatalf("expected 0, got %d", len(txns)) + } + }) } diff --git a/p2p/rpc/debugapi/v1/debugapi.proto b/p2p/rpc/debugapi/v1/debugapi.proto new file mode 100644 index 000000000..d13119052 --- /dev/null +++ b/p2p/rpc/debugapi/v1/debugapi.proto @@ -0,0 +1,131 @@ +syntax = "proto3"; + +package debugapi.v1; + +import "protoc-gen-openapiv2/options/annotations.proto"; +import "google/api/annotations.proto"; +import "google/protobuf/struct.proto"; +import "buf/validate/validate.proto"; + +option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { + info: { + title: "Debug API"; + version: "1.0.0-alpha"; + license: { + name: "Business Source License 1.1"; + url: "https://github.com/primev/mev-commit/blob/main/LICENSE"; + }; + }; +}; + +service DebugService { + // GetTopology + // + // GetTopology is called by the user to get the topology of the node. The topology + // includes connectivity information about the node. + rpc GetTopology(EmptyMessage) returns (TopologyResponse) { + option (google.api.http) = {get: "/v1/debug/topology"}; + } + // GetPendingTransactions + // + // GetPendingTransactions is called by the provider to get the pending transactions for the wallet. + rpc GetPendingTransactions(EmptyMessage) returns (PendingTransactionsResponse) { + option (google.api.http) = {get: "/v1/debug/pending_transactions"}; + } + // CancelTransaction + // + // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. + rpc CancelTransaction(CancelTransactionReq) returns (CancelTransactionResponse) { + option (google.api.http) = {post: "/v1/debug/cancel_transaction/{tx_hash}"}; + } +} + +message EmptyMessage { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Empty message" + description: "Empty message for requests that do not require any parameters." + } + }; +}; + +message TopologyResponse { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Topology" + description: "Topology of the node." + required: ["topology"] + } + }; + google.protobuf.Struct topology = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Topology of the node." + }]; +}; + +message PendingTransactionsResponse { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Pending transactions list" + description: "Transaction info returned by the provider." + required: ["pendingTransactions"] + } + }; + repeated TransactionInfo pending_transactions = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "List of pending transactions in the provider provider_registry." + }]; +}; + +message TransactionInfo { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Transaction info" + description: "Transaction info returned by the provider." + required: ["txHash", "nonce", "created"] + } + example: "{\"txHash\": \"71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8\", \"nonce\": 1234, \"created\": \"2009-11-10 23:00:00 +0000 UTC m=+0.000000001\"}" + }; + string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Hex string encoding of the hash of the transaction that the bidder wants to include in the block." + pattern: "[a-fA-F0-9]{64}" + }]; + int64 nonce = 2 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Nonce used for the transaction." + }]; + string created = 3 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Time when the transaction was created." + }]; +}; + +message CancelTransactionReq { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Cancel request" + description: "Cancel transaction request message from bidders to the provider." + required: ["txHash"] + } + example: "{\"txHash\": \"71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8\"}" + }; + string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Hex string encoding of the hash of the transaction that the bidder wants to cancel." + pattern: "[a-fA-F0-9]{64}" + }, (buf.validate.field).cel = { + id: "tx_hash", + message: "tx_hash must be a 64-character hex string", + expression: "this.matches('^[a-fA-F0-9]{64}$')" + }]; +}; + +message CancelTransactionResponse { + option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { + json_schema: { + title: "Cancel response" + description: "Hash of the cancellation transaction request." + required: ["txHash"] + } + example: "{\"txHash\": \"71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8\"}" + }; + string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { + description: "Hex string encoding of the hash of the transaction that the bidder wants to cancel." + pattern: "[a-fA-F0-9]{64}" + }]; +}; diff --git a/p2p/rpc/providerapi/v1/providerapi.proto b/p2p/rpc/providerapi/v1/providerapi.proto index c0afae50d..a49965d08 100644 --- a/p2p/rpc/providerapi/v1/providerapi.proto +++ b/p2p/rpc/providerapi/v1/providerapi.proto @@ -53,18 +53,6 @@ service Provider { rpc GetMinStake(EmptyMessage) returns (StakeResponse) { option (google.api.http) = {get: "/v1/provider/get_min_stake"}; } - // GetPendingTxns - // - // GetPendingTxns is called by the provider to get the pending transactions for the wallet. - rpc GetPendingTxns(EmptyMessage) returns (PendingTxnsResponse) { - option (google.api.http) = {get: "/v1/provider/get_pending_txns"}; - } - // CancelTransaction - // - // CancelTransaction is called by the provider to cancel a transaction sent from this wallet. - rpc CancelTransaction(CancelReq) returns (CancelResponse) { - option (google.api.http) = {post: "/v1/provider/cancel_transaction/{tx_hash}"}; - } } message StakeRequest { @@ -178,67 +166,3 @@ message BidResponse { description: "Timestamp at which the commitment is accepted by provider and is used to compute the expected revenue from the preconfirmation" }]; }; - -message PendingTxnsResponse { - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { - json_schema: { - title: "Pending transactions list" - description: "Transaction info returned by the provider." - required: ["pendingTxns"] - } - }; - repeated TransactionInfo pending_txns = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "List of pending transactions in the provider provider_registry." - }]; -}; - -message TransactionInfo { - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { - json_schema: { - title: "Transaction info" - description: "Transaction info returned by the provider." - required: ["txHash", "nonce", "created"] - } - example: "{\"txHash\": \"71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8\", \"nonce\": 1234, \"created\": \"2009-11-10 23:00:00 +0000 UTC m=+0.000000001\"}" - }; - string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Hex string encoding of the hash of the transaction that the bidder wants to include in the block." - pattern: "[a-fA-F0-9]{64}" - }]; - int64 nonce = 2 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Nonce used for the transaction." - }]; - string created = 3 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Time when the transaction was created." - }]; -}; - -message CancelReq { - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { - json_schema: { - title: "Cancel request" - description: "Cancel transaction request message from bidders to the provider." - required: ["txHash"] - } - example: "{\"txHash\": \"91a89B633194c0D86C539A1A5B14DCCacfD47094\"}" - }; - string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Hex string encoding of the hash of the transaction that the bidder wants to cancel." - pattern: "[a-fA-F0-9]{64}" - }]; -}; - -message CancelResponse { - option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_schema) = { - json_schema: { - title: "Cancel response" - description: "Hash of the cancellation transaction request." - required: ["txHash"] - } - example: "{\"txHash\": \"71c1348f2d7ff7e814f9c3617983703435ea7446de420aeac488bf1de35737e8\"}" - }; - string tx_hash = 1 [(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = { - description: "Hex string encoding of the hash of the transaction that the bidder wants to cancel." - pattern: "[a-fA-F0-9]{64}" - }]; -}; diff --git a/x/contracts/transactor/transactor.go b/x/contracts/transactor/transactor.go index 5791481ad..d3253a8dc 100644 --- a/x/contracts/transactor/transactor.go +++ b/x/contracts/transactor/transactor.go @@ -2,6 +2,7 @@ package transactor import ( "context" + "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -85,7 +86,28 @@ func (t *Transactor) SendTransaction(ctx context.Context, tx *types.Transaction) return ctx.Err() } - if err := t.ContractTransactor.SendTransaction(ctx, tx); err != nil { + tries := 0 + delay := 1 * time.Second +retry: + cctx, cancel := context.WithTimeout(ctx, 5*time.Second) + defer cancel() + + if err := t.ContractTransactor.SendTransaction(cctx, tx); err != nil { + if err == context.DeadlineExceeded { + tries++ + if tries < 3 { + // If the transaction fails due to a timeout, we can retry it. + delay *= 2 + retryTimer := time.NewTimer(delay) + select { + case <-ctx.Done(): + return ctx.Err() + case <-retryTimer.C: + _ = retryTimer.Stop() + goto retry + } + } + } return err } diff --git a/x/contracts/txmonitor/canceller.go b/x/contracts/txmonitor/canceller.go new file mode 100644 index 000000000..42f17fcca --- /dev/null +++ b/x/contracts/txmonitor/canceller.go @@ -0,0 +1,117 @@ +package txmonitor + +import ( + "context" + "fmt" + "log/slog" + "math/big" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/primev/mev-commit/x/keysigner" +) + +type Canceller struct { + chainID *big.Int + ethClient *ethclient.Client + keySigner keysigner.KeySigner + monitor *Monitor + logger *slog.Logger +} + +func NewCanceller( + chainID *big.Int, + ethClient *ethclient.Client, + keySigner keysigner.KeySigner, + monitor *Monitor, + logger *slog.Logger, +) *Canceller { + return &Canceller{ + chainID: chainID, + ethClient: ethClient, + keySigner: keySigner, + monitor: monitor, + logger: logger, + } +} + +func (c *Canceller) suggestMaxFeeAndTipCap( + ctx context.Context, + gasPrice *big.Int, +) (*big.Int, *big.Int, error) { + // Returns priority fee per gas + gasTipCap, err := c.ethClient.SuggestGasTipCap(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to suggest gas tip cap: %w", err) + } + + // Returns priority fee per gas + base fee per gas + if gasPrice == nil { + gasPrice, err = c.ethClient.SuggestGasPrice(ctx) + if err != nil { + return nil, nil, fmt.Errorf("failed to suggest gas price: %w", err) + } + } + + return gasPrice, gasTipCap, nil +} + +func (c *Canceller) CancelTx(ctx context.Context, txnHash common.Hash) (common.Hash, error) { + txn, isPending, err := c.ethClient.TransactionByHash(ctx, txnHash) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to get transaction: %w", err) + } + + if !isPending { + return common.Hash{}, ethereum.NotFound + } + + gasFeeCap, gasTipCap, err := c.suggestMaxFeeAndTipCap(ctx, txn.GasPrice()) + if err != nil { + return common.Hash{}, fmt.Errorf("failed to suggest max fee and tip cap: %w", err) + } + + if gasFeeCap.Cmp(txn.GasFeeCap()) <= 0 { + gasFeeCap = txn.GasFeeCap() + } + + if gasTipCap.Cmp(txn.GasTipCap()) <= 0 { + gasTipCap = txn.GasTipCap() + } + + // increase gas fee cap and tip cap by 10% for better chance of replacing + gasTipCap = new(big.Int).Div(new(big.Int).Mul(gasTipCap, big.NewInt(110)), big.NewInt(100)) + gasFeeCap = new(big.Int).Div(new(big.Int).Mul(gasFeeCap, big.NewInt(110)), big.NewInt(100)) + + owner := c.keySigner.GetAddress() + + tx := types.NewTx(&types.DynamicFeeTx{ + Nonce: txn.Nonce(), + ChainID: c.chainID, + To: &owner, + Value: big.NewInt(0), + Gas: 21000, + GasFeeCap: gasFeeCap, + GasTipCap: gasTipCap, + Data: []byte{}, + }) + + signedTx, err := c.keySigner.SignTx(tx, c.chainID) + if err != nil { + c.logger.Error("failed to sign cancel tx", "err", err) + return common.Hash{}, fmt.Errorf("failed to sign cancel tx: %w", err) + } + + err = c.ethClient.SendTransaction(ctx, signedTx) + if err != nil { + c.logger.Error("failed to send cancel tx", "err", err) + return common.Hash{}, err + } + + c.logger.Info("sent cancel txn", "txHash", signedTx.Hash().Hex()) + c.monitor.Sent(ctx, signedTx) + + return signedTx.Hash(), nil +} diff --git a/x/contracts/txmonitor/txmonitor.go b/x/contracts/txmonitor/txmonitor.go index c43869ecf..a3a333b3c 100644 --- a/x/contracts/txmonitor/txmonitor.go +++ b/x/contracts/txmonitor/txmonitor.go @@ -230,6 +230,16 @@ func (m *Monitor) WatchTx(txHash common.Hash, nonce uint64) <-chan Result { return c } +func (m *Monitor) WaitForReceipt(ctx context.Context, tx *types.Transaction) (*types.Receipt, error) { + res := m.WatchTx(tx.Hash(), tx.Nonce()) + select { + case <-ctx.Done(): + return nil, ctx.Err() + case r := <-res: + return r.Receipt, r.Err + } +} + func (m *Monitor) triggerNewTx() { select { case m.newTxAdded <- struct{}{}: diff --git a/x/keysigner/keysigner.go b/x/keysigner/keysigner.go index 3b7cc551b..f848c8c75 100644 --- a/x/keysigner/keysigner.go +++ b/x/keysigner/keysigner.go @@ -1,6 +1,7 @@ package keysigner import ( + "context" "crypto/ecdsa" "fmt" "math/big" @@ -19,4 +20,5 @@ type KeySigner interface { GetPrivateKey() (*ecdsa.PrivateKey, error) ZeroPrivateKey(key *ecdsa.PrivateKey) GetAuth(chainID *big.Int) (*bind.TransactOpts, error) + GetAuthWithCtx(ctx context.Context, chainID *big.Int) (*bind.TransactOpts, error) } diff --git a/x/keysigner/keystoresigner.go b/x/keysigner/keystoresigner.go index a0fa0e149..6c69bee5d 100644 --- a/x/keysigner/keystoresigner.go +++ b/x/keysigner/keystoresigner.go @@ -1,6 +1,7 @@ package keysigner import ( + "context" "crypto/ecdsa" "fmt" "math/big" @@ -78,3 +79,13 @@ func (kss *KeystoreSigner) GetAuth(chainID *big.Int) (*bind.TransactOpts, error) return bind.NewKeyStoreTransactorWithChainID(kss.keystore, kss.account, chainID) } + +func (kss *KeystoreSigner) GetAuthWithCtx(ctx context.Context, chainID *big.Int) (*bind.TransactOpts, error) { + opts, err := kss.GetAuth(chainID) + if err != nil { + return nil, err + } + + opts.Context = ctx + return opts, nil +} diff --git a/x/keysigner/mock/mock.go b/x/keysigner/mock/mock.go index f34cc1b38..8c8bb30fd 100644 --- a/x/keysigner/mock/mock.go +++ b/x/keysigner/mock/mock.go @@ -1,6 +1,7 @@ package mockkeysigner import ( + "context" "crypto/ecdsa" "math/big" @@ -44,3 +45,7 @@ func (m *MockKeySigner) String() string { func (m *MockKeySigner) GetAuth(chainID *big.Int) (*bind.TransactOpts, error) { return nil, nil } + +func (m *MockKeySigner) GetAuthWithCtx(_ context.Context, chainID *big.Int) (*bind.TransactOpts, error) { + return nil, nil +} diff --git a/x/keysigner/privatekeysigner.go b/x/keysigner/privatekeysigner.go index 42445ab04..ccbfae319 100644 --- a/x/keysigner/privatekeysigner.go +++ b/x/keysigner/privatekeysigner.go @@ -1,6 +1,7 @@ package keysigner import ( + "context" "crypto/ecdsa" "fmt" "math/big" @@ -61,6 +62,15 @@ func (pks *PrivateKeySigner) GetAuth(chainID *big.Int) (*bind.TransactOpts, erro return bind.NewKeyedTransactorWithChainID(pks.privKey, chainID) } +func (pks *PrivateKeySigner) GetAuthWithCtx(ctx context.Context, chainID *big.Int) (*bind.TransactOpts, error) { + opts, err := pks.GetAuth(chainID) + if err != nil { + return nil, err + } + opts.Context = ctx + return opts, nil +} + // ZeroPrivateKey does nothing because the private key for PKS persists in memory // and should not be deleted. func (pks *PrivateKeySigner) ZeroPrivateKey(key *ecdsa.PrivateKey) {}