From 980a63d2a4a17ce41535106b99f67c442d0c0b8f Mon Sep 17 00:00:00 2001 From: "Dima K." Date: Fri, 24 Jan 2025 12:34:13 -0800 Subject: [PATCH 1/5] [Upgrade] Alpha TestNet v0.0.11 (#967) ## Summary An upgrade for Alpha TestNet from v0.0.10 to v0.0.11. ## Issue Beta TestNet has been launched using v0.0.11 (release candidate), and we need to upgrade alpha so both networks use the same version. ## Type of change Chain upgrade. ## Testing - [] An upgrade is tested by upgrading a network provisioned by the old version (v0.0.10) to the new version (v0.0.11) ## Sanity Checklist - [ ] I have tested my changes using the available tooling - [ ] I have commented my code - [ ] I have performed a self-review of my own code; both comments & source code - [ ] I create and reference any new tickets, if applicable - [ ] I have left TODOs throughout the codebase, if applicable --------- Co-authored-by: Daniel Olshansky --- app/upgrades.go | 1 + app/upgrades/v0.0.11.go | 98 +++++++++++++++++++++++++++++++++++++ cmd/poktrolld/cmd/config.go | 8 ++- telemetry/defaults.go | 14 ++++++ telemetry/telemetry.go | 23 +++++++-- 5 files changed, 135 insertions(+), 9 deletions(-) create mode 100644 app/upgrades/v0.0.11.go create mode 100644 telemetry/defaults.go diff --git a/app/upgrades.go b/app/upgrades.go index 42582dc2b..df4543c99 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -13,6 +13,7 @@ import ( var allUpgrades = []upgrades.Upgrade{ upgrades.Upgrade_0_0_4, upgrades.Upgrade_0_0_10, + upgrades.Upgrade_0_0_11, } // setUpgrades sets upgrade handlers for all upgrades and executes KVStore migration if an upgrade plan file exists. diff --git a/app/upgrades/v0.0.11.go b/app/upgrades/v0.0.11.go new file mode 100644 index 000000000..615feecef --- /dev/null +++ b/app/upgrades/v0.0.11.go @@ -0,0 +1,98 @@ +package upgrades + +import ( + "context" + + storetypes "cosmossdk.io/store/types" + upgradetypes "cosmossdk.io/x/upgrade/types" + cosmosTypes "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/pokt-network/poktroll/app/keepers" + sessiontypes "github.com/pokt-network/poktroll/x/session/types" + tokenomicstypes "github.com/pokt-network/poktroll/x/tokenomics/types" +) + +// Upgrade_0_0_11 is the upgrade handler for v0.0.11 Alpha TestNet upgrade +// Beta TestNet was launched with v0.0.11, so this upgrade is exclusively for Alpha TestNet. +// - Before: v0.0.10 +// - After: v0.0.11 +var Upgrade_0_0_11 = Upgrade{ + PlanName: "v0.0.11", + CreateUpgradeHandler: func(mm *module.Manager, + keepers *keepers.Keepers, + configurator module.Configurator, + ) upgradetypes.UpgradeHandler { + // Adds new parameters using ignite's config.yml as a reference. Assuming we don't need any other parameters. + // https://github.com/pokt-network/poktroll/compare/v0.0.10...v0.0.11-rc + applyNewParameters := func(ctx context.Context) (err error) { + logger := cosmosTypes.UnwrapSDKContext(ctx).Logger() + logger.Info("Starting parameter updates for v0.0.11") + + // Set num_suppliers_per_session to 15 + // Validate with: `poktrolld q session params --node=https://testnet-validated-validator-rpc.poktroll.com/` + sessionParams := sessiontypes.Params{ + NumSuppliersPerSession: uint64(15), + } + + // ALL parameters must be present when setting params. + err = keepers.SessionKeeper.SetParams(ctx, sessionParams) + if err != nil { + logger.Error("Failed to set session params", "error", err) + return err + } + logger.Info("Successfully updated session params", "new_params", sessionParams) + + // Set tokenomics params. The values are based on default values for LocalNet/Beta TestNet. + // Validate with: `poktrolld q tokenomics params --node=https://testnet-validated-validator-rpc.poktroll.com/` + tokenomicsParams := tokenomicstypes.Params{ + MintAllocationPercentages: tokenomicstypes.MintAllocationPercentages{ + Dao: 0.1, + Proposer: 0.05, + Supplier: 0.7, + SourceOwner: 0.15, + Application: 0.0, + }, + DaoRewardAddress: AlphaTestNetPnfAddress, + } + + // ALL parameters must be present when setting params. + err = keepers.TokenomicsKeeper.SetParams(ctx, tokenomicsParams) + if err != nil { + logger.Error("Failed to set tokenomics params", "error", err) + return err + } + logger.Info("Successfully updated tokenomics params", "new_params", tokenomicsParams) + + return + } + + // The diff shows that the only new authz authorization is for the `poktroll.session.MsgUpdateParam` message. + // However, this message is already authorized for the `pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t` address. + // See here: poktrolld q authz grants-by-granter pokt10d07y265gmmuvt4z0w9aw880jnsr700j8yv32t --node=https://shannon-testnet-grove-seed-rpc.alpha.poktroll.com + // If this upgrade would have been applied to other networks, we could have added a separate upgrade handler for each network. + + // Returns the upgrade handler for v0.0.11 + return func(ctx context.Context, plan upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + logger := cosmosTypes.UnwrapSDKContext(ctx).Logger() + logger.Info("Starting v0.0.11 upgrade handler") + + err := applyNewParameters(ctx) + if err != nil { + logger.Error("Failed to apply new parameters", "error", err) + return vm, err + } + + logger.Info("Running module migrations") + vm, err = mm.RunMigrations(ctx, configurator, vm) + if err != nil { + logger.Error("Failed to run migrations", "error", err) + return vm, err + } + + logger.Info("Successfully completed v0.0.11 upgrade handler") + return vm, nil + } + }, + // No changes to the KVStore in this upgrade. + StoreUpgrades: storetypes.StoreUpgrades{}, +} diff --git a/cmd/poktrolld/cmd/config.go b/cmd/poktrolld/cmd/config.go index ae9520a41..89536a6a1 100644 --- a/cmd/poktrolld/cmd/config.go +++ b/cmd/poktrolld/cmd/config.go @@ -21,12 +21,10 @@ type PoktrollAppConfig struct { } // poktrollAppConfigDefaults sets default values to render in `app.toml`. -// Checkout `customAppConfigTemplate()` for additional information about each setting. +// Checkout `customAppConfigTemplate()` for additional information about each config parameter. func poktrollAppConfigDefaults() PoktrollAppConfig { return PoktrollAppConfig{ - Telemetry: telemetry.PoktrollTelemetryConfig{ - CardinalityLevel: "medium", - }, + Telemetry: telemetry.DefaultConfig(), } } @@ -104,7 +102,6 @@ func initCometBFTConfig() *cmtcfg.Config { // return "", nil if no custom configuration is required for the application. // TODO_MAINNET: Reconsider values - check `app.toml` for possible options. func initAppConfig() (string, interface{}) { - // The following code snippet is just for reference. type CustomAppConfig struct { serverconfig.Config `mapstructure:",squash"` Poktroll PoktrollAppConfig `mapstructure:"poktroll"` @@ -140,6 +137,7 @@ func initAppConfig() (string, interface{}) { srvCfg.GRPC.Enable = true srvCfg.GRPCWeb.Enable = true + // Create the custom config with both server and poktroll configs customAppConfig := CustomAppConfig{ Config: *srvCfg, Poktroll: poktrollAppConfigDefaults(), diff --git a/telemetry/defaults.go b/telemetry/defaults.go new file mode 100644 index 000000000..e059e2c93 --- /dev/null +++ b/telemetry/defaults.go @@ -0,0 +1,14 @@ +package telemetry + +// Default configuration values for telemetry +const ( + // DefaultCardinalityLevel represents the default cardinality level for metrics collection + DefaultCardinalityLevel = "medium" +) + +// DefaultConfig returns the default telemetry configuration +func DefaultConfig() PoktrollTelemetryConfig { + return PoktrollTelemetryConfig{ + CardinalityLevel: DefaultCardinalityLevel, + } +} diff --git a/telemetry/telemetry.go b/telemetry/telemetry.go index 348b73898..d7b93a879 100644 --- a/telemetry/telemetry.go +++ b/telemetry/telemetry.go @@ -11,16 +11,31 @@ import ( // Set once on initialization and remains constant during runtime. var globalTelemetryConfig PoktrollTelemetryConfig -// PoktrollTelemetryConfig represents the telemetry protion of the custom poktroll config section in `app.toml`. +// PoktrollTelemetryConfig represents the telemetry portion of the custom poktroll config section in `app.toml`. type PoktrollTelemetryConfig struct { CardinalityLevel string `mapstructure:"cardinality-level"` } // New sets the globalTelemetryConfig for telemetry package. func New(appOpts servertypes.AppOptions) error { - // Extract the map from appOpts. - // `poktroll.telemetry` comes from `app.toml` which is parsed into a map. - telemetryMap := appOpts.Get("poktroll.telemetry").(map[string]interface{}) + // Get the poktroll config section. If it doesn't exist, use defaults + poktrollConfig := appOpts.Get("poktroll") + if poktrollConfig == nil { + globalTelemetryConfig = DefaultConfig() + return nil + } + + // Try to get the telemetry subsection + poktrollMap, ok := poktrollConfig.(map[string]interface{}) + if !ok { + return fmt.Errorf("invalid poktroll config format: expected map[string]interface{}, got %T", poktrollConfig) + } + + telemetryMap, ok := poktrollMap["telemetry"].(map[string]interface{}) + if !ok { + globalTelemetryConfig = DefaultConfig() + return nil + } // Use mapstructure to decode the map into the struct if err := mapstructure.Decode(telemetryMap, &globalTelemetryConfig); err != nil { From 43a9a3d4a3dfebb57a134458c1ac2b005d621aca Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 29 Jan 2025 12:57:41 +0100 Subject: [PATCH 2/5] chore: Address reivew change requests --- api/poktroll/proof/event.pulsar.go | 9 +- api/poktroll/proof/types.pulsar.go | 146 ++++++++++--------- proto/poktroll/proof/event.proto | 5 +- proto/poktroll/proof/types.proto | 21 +-- testutil/testtree/tree.go | 2 +- x/proof/keeper/msg_server_submit_proof.go | 23 ++- x/proof/keeper/proof_validation.go | 30 ++-- x/proof/keeper/validate_proofs.go | 82 +++++------ x/proof/module/abci.go | 6 +- x/proof/types/event.pb.go | 9 +- x/proof/types/types.pb.go | 118 +++++++-------- x/tokenomics/keeper/settle_pending_claims.go | 18 +-- 12 files changed, 240 insertions(+), 229 deletions(-) diff --git a/api/poktroll/proof/event.pulsar.go b/api/poktroll/proof/event.pulsar.go index dd7b048a8..fa9a83ea1 100644 --- a/api/poktroll/proof/event.pulsar.go +++ b/api/poktroll/proof/event.pulsar.go @@ -3698,7 +3698,8 @@ func (x *EventProofUpdated) GetClaimedUpokt() *v1beta1.Coin { return nil } -// Event emitted after a proof has been checked for validity. +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. type EventProofValidityChecked struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -3707,7 +3708,9 @@ type EventProofValidityChecked struct { Proof *Proof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof,omitempty"` BlockHeight uint64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height,omitempty"` ProofStatus ClaimProofStatus `protobuf:"varint,3,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status,omitempty"` - Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason,omitempty"` } func (x *EventProofValidityChecked) Reset() { @@ -3748,7 +3751,7 @@ func (x *EventProofValidityChecked) GetProofStatus() ClaimProofStatus { if x != nil { return x.ProofStatus } - return ClaimProofStatus_NOT_FOUND + return ClaimProofStatus_PENDING_VALIDATION } func (x *EventProofValidityChecked) GetReason() string { diff --git a/api/poktroll/proof/types.pulsar.go b/api/poktroll/proof/types.pulsar.go index 2498a8038..a49834e88 100644 --- a/api/poktroll/proof/types.pulsar.go +++ b/api/poktroll/proof/types.pulsar.go @@ -585,7 +585,7 @@ var ( fd_Claim_supplier_operator_address protoreflect.FieldDescriptor fd_Claim_session_header protoreflect.FieldDescriptor fd_Claim_root_hash protoreflect.FieldDescriptor - fd_Claim_proof_status protoreflect.FieldDescriptor + fd_Claim_proof_validation_status protoreflect.FieldDescriptor ) func init() { @@ -594,7 +594,7 @@ func init() { fd_Claim_supplier_operator_address = md_Claim.Fields().ByName("supplier_operator_address") fd_Claim_session_header = md_Claim.Fields().ByName("session_header") fd_Claim_root_hash = md_Claim.Fields().ByName("root_hash") - fd_Claim_proof_status = md_Claim.Fields().ByName("proof_status") + fd_Claim_proof_validation_status = md_Claim.Fields().ByName("proof_validation_status") } var _ protoreflect.Message = (*fastReflection_Claim)(nil) @@ -680,9 +680,9 @@ func (x *fastReflection_Claim) Range(f func(protoreflect.FieldDescriptor, protor return } } - if x.ProofStatus != 0 { - value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.ProofStatus)) - if !f(fd_Claim_proof_status, value) { + if x.ProofValidationStatus != 0 { + value := protoreflect.ValueOfEnum((protoreflect.EnumNumber)(x.ProofValidationStatus)) + if !f(fd_Claim_proof_validation_status, value) { return } } @@ -707,8 +707,8 @@ func (x *fastReflection_Claim) Has(fd protoreflect.FieldDescriptor) bool { return x.SessionHeader != nil case "poktroll.proof.Claim.root_hash": return len(x.RootHash) != 0 - case "poktroll.proof.Claim.proof_status": - return x.ProofStatus != 0 + case "poktroll.proof.Claim.proof_validation_status": + return x.ProofValidationStatus != 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -731,8 +731,8 @@ func (x *fastReflection_Claim) Clear(fd protoreflect.FieldDescriptor) { x.SessionHeader = nil case "poktroll.proof.Claim.root_hash": x.RootHash = nil - case "poktroll.proof.Claim.proof_status": - x.ProofStatus = 0 + case "poktroll.proof.Claim.proof_validation_status": + x.ProofValidationStatus = 0 default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -758,8 +758,8 @@ func (x *fastReflection_Claim) Get(descriptor protoreflect.FieldDescriptor) prot case "poktroll.proof.Claim.root_hash": value := x.RootHash return protoreflect.ValueOfBytes(value) - case "poktroll.proof.Claim.proof_status": - value := x.ProofStatus + case "poktroll.proof.Claim.proof_validation_status": + value := x.ProofValidationStatus return protoreflect.ValueOfEnum((protoreflect.EnumNumber)(value)) default: if descriptor.IsExtension() { @@ -787,8 +787,8 @@ func (x *fastReflection_Claim) Set(fd protoreflect.FieldDescriptor, value protor x.SessionHeader = value.Message().Interface().(*session.SessionHeader) case "poktroll.proof.Claim.root_hash": x.RootHash = value.Bytes() - case "poktroll.proof.Claim.proof_status": - x.ProofStatus = (ClaimProofStatus)(value.Enum()) + case "poktroll.proof.Claim.proof_validation_status": + x.ProofValidationStatus = (ClaimProofStatus)(value.Enum()) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -818,8 +818,8 @@ func (x *fastReflection_Claim) Mutable(fd protoreflect.FieldDescriptor) protoref panic(fmt.Errorf("field supplier_operator_address of message poktroll.proof.Claim is not mutable")) case "poktroll.proof.Claim.root_hash": panic(fmt.Errorf("field root_hash of message poktroll.proof.Claim is not mutable")) - case "poktroll.proof.Claim.proof_status": - panic(fmt.Errorf("field proof_status of message poktroll.proof.Claim is not mutable")) + case "poktroll.proof.Claim.proof_validation_status": + panic(fmt.Errorf("field proof_validation_status of message poktroll.proof.Claim is not mutable")) default: if fd.IsExtension() { panic(fmt.Errorf("proto3 declared messages do not support extensions: poktroll.proof.Claim")) @@ -840,7 +840,7 @@ func (x *fastReflection_Claim) NewField(fd protoreflect.FieldDescriptor) protore return protoreflect.ValueOfMessage(m.ProtoReflect()) case "poktroll.proof.Claim.root_hash": return protoreflect.ValueOfBytes(nil) - case "poktroll.proof.Claim.proof_status": + case "poktroll.proof.Claim.proof_validation_status": return protoreflect.ValueOfEnum(0) default: if fd.IsExtension() { @@ -923,8 +923,8 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { if l > 0 { n += 1 + l + runtime.Sov(uint64(l)) } - if x.ProofStatus != 0 { - n += 1 + runtime.Sov(uint64(x.ProofStatus)) + if x.ProofValidationStatus != 0 { + n += 1 + runtime.Sov(uint64(x.ProofValidationStatus)) } if x.unknownFields != nil { n += len(x.unknownFields) @@ -955,8 +955,8 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { i -= len(x.unknownFields) copy(dAtA[i:], x.unknownFields) } - if x.ProofStatus != 0 { - i = runtime.EncodeVarint(dAtA, i, uint64(x.ProofStatus)) + if x.ProofValidationStatus != 0 { + i = runtime.EncodeVarint(dAtA, i, uint64(x.ProofValidationStatus)) i-- dAtA[i] = 0x20 } @@ -1141,9 +1141,9 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { iNdEx = postIndex case 4: if wireType != 0 { - return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ProofStatus", wireType) + return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, fmt.Errorf("proto: wrong wireType = %d for field ProofValidationStatus", wireType) } - x.ProofStatus = 0 + x.ProofValidationStatus = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return protoiface.UnmarshalOutput{NoUnkeyedLiterals: input.NoUnkeyedLiterals, Flags: input.Flags}, runtime.ErrIntOverflow @@ -1153,7 +1153,7 @@ func (x *fastReflection_Claim) ProtoMethods() *protoiface.Methods { } b := dAtA[iNdEx] iNdEx++ - x.ProofStatus |= ClaimProofStatus(b&0x7F) << shift + x.ProofValidationStatus |= ClaimProofStatus(b&0x7F) << shift if b < 0x80 { break } @@ -1311,27 +1311,27 @@ func (ClaimProofStage) EnumDescriptor() ([]byte, []int) { return file_poktroll_proof_types_proto_rawDescGZIP(), []int{1} } -// ClaimProofStatus defines the status of the proof for a claim. -// The default value is NOT_FOUND, whether the proof is required or not. +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement type ClaimProofStatus int32 const ( - ClaimProofStatus_NOT_FOUND ClaimProofStatus = 0 - ClaimProofStatus_VALID ClaimProofStatus = 1 - ClaimProofStatus_INVALID ClaimProofStatus = 2 + ClaimProofStatus_PENDING_VALIDATION ClaimProofStatus = 0 + ClaimProofStatus_VALIDATED ClaimProofStatus = 1 + ClaimProofStatus_INVALID ClaimProofStatus = 2 ) // Enum value maps for ClaimProofStatus. var ( ClaimProofStatus_name = map[int32]string{ - 0: "NOT_FOUND", - 1: "VALID", + 0: "PENDING_VALIDATION", + 1: "VALIDATED", 2: "INVALID", } ClaimProofStatus_value = map[string]int32{ - "NOT_FOUND": 0, - "VALID": 1, - "INVALID": 2, + "PENDING_VALIDATION": 0, + "VALIDATED": 1, + "INVALID": 2, } ) @@ -1422,14 +1422,14 @@ type Claim struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + // Address of the supplier's operator that submitted this claim. SupplierOperatorAddress string `protobuf:"bytes,1,opt,name=supplier_operator_address,json=supplierOperatorAddress,proto3" json:"supplier_operator_address,omitempty"` // the address of the supplier's operator that submitted this claim - // The session header of the session that this claim is for. + // Session header this claim is for. SessionHeader *session.SessionHeader `protobuf:"bytes,2,opt,name=session_header,json=sessionHeader,proto3" json:"session_header,omitempty"` - // Root hash returned from smt.SMST#Root(). + // Root hash from smt.SMST#Root(). RootHash []byte `protobuf:"bytes,3,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` - // Claim proof status captures the status of the proof for this claim. - // WARNING: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath - ProofStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status,omitempty"` + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ProofValidationStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_validation_status,json=proofValidationStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_validation_status,omitempty"` } func (x *Claim) Reset() { @@ -1473,11 +1473,11 @@ func (x *Claim) GetRootHash() []byte { return nil } -func (x *Claim) GetProofStatus() ClaimProofStatus { +func (x *Claim) GetProofValidationStatus() ClaimProofStatus { if x != nil { - return x.ProofStatus + return x.ProofValidationStatus } - return ClaimProofStatus_NOT_FOUND + return ClaimProofStatus_PENDING_VALIDATION } var File_poktroll_proof_types_proto protoreflect.FileDescriptor @@ -1504,7 +1504,7 @@ var file_poktroll_proof_types_proto_rawDesc = []byte{ 0x64, 0x65, 0x72, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x73, 0x74, 0x5f, 0x6d, 0x65, 0x72, 0x6b, 0x6c, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x12, 0x63, 0x6c, 0x6f, 0x73, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x72, 0x6b, 0x6c, 0x65, - 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x87, 0x02, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, + 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x22, 0x9c, 0x02, 0x0a, 0x05, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x12, 0x54, 0x0a, 0x19, 0x73, 0x75, 0x70, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x5f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x18, 0xd2, 0xb4, 0x2d, 0x14, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x2e, 0x41, @@ -1516,35 +1516,37 @@ var file_poktroll_proof_types_proto_rawDesc = []byte{ 0x2e, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x52, 0x0d, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x6f, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x43, 0x0a, 0x0c, 0x70, 0x72, - 0x6f, 0x6f, 0x66, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x20, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, - 0x66, 0x2e, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x52, 0x0b, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2a, - 0x4c, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x6d, - 0x65, 0x6e, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x0c, 0x4e, 0x4f, 0x54, - 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x50, - 0x52, 0x4f, 0x42, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x53, 0x54, 0x49, 0x43, 0x10, 0x01, 0x12, 0x0d, - 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, 0x10, 0x02, 0x2a, 0x44, 0x0a, - 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x67, 0x65, - 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, - 0x06, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x45, 0x54, - 0x54, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, 0x58, 0x50, 0x49, 0x52, 0x45, - 0x44, 0x10, 0x03, 0x2a, 0x39, 0x0a, 0x10, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x54, 0x5f, 0x46, - 0x4f, 0x55, 0x4e, 0x44, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, - 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, 0x42, 0x9e, - 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x73, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, 0x73, 0x73, - 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, 0x72, 0x6f, - 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, 0xaa, 0x02, - 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0xca, - 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, 0x66, - 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, 0x6f, - 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0f, - 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x62, - 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x52, 0x08, 0x72, 0x6f, 0x6f, 0x74, 0x48, 0x61, 0x73, 0x68, 0x12, 0x58, 0x0a, 0x17, 0x70, 0x72, + 0x6f, 0x6f, 0x66, 0x5f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x6f, + 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x2e, 0x43, 0x6c, 0x61, + 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x15, 0x70, + 0x72, 0x6f, 0x6f, 0x66, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x2a, 0x4c, 0x0a, 0x16, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x52, 0x65, 0x71, + 0x75, 0x69, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x10, + 0x0a, 0x0c, 0x4e, 0x4f, 0x54, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x49, 0x52, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x11, 0x0a, 0x0d, 0x50, 0x52, 0x4f, 0x42, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x53, 0x54, 0x49, + 0x43, 0x10, 0x01, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x48, 0x52, 0x45, 0x53, 0x48, 0x4f, 0x4c, 0x44, + 0x10, 0x02, 0x2a, 0x44, 0x0a, 0x0f, 0x43, 0x6c, 0x61, 0x69, 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, + 0x53, 0x74, 0x61, 0x67, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x4c, 0x41, 0x49, 0x4d, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x52, 0x4f, 0x56, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0b, + 0x0a, 0x07, 0x53, 0x45, 0x54, 0x54, 0x4c, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0b, 0x0a, 0x07, 0x45, + 0x58, 0x50, 0x49, 0x52, 0x45, 0x44, 0x10, 0x03, 0x2a, 0x46, 0x0a, 0x10, 0x43, 0x6c, 0x61, 0x69, + 0x6d, 0x50, 0x72, 0x6f, 0x6f, 0x66, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x12, + 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x5f, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x41, 0x54, 0x45, + 0x44, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x02, + 0x42, 0x9e, 0x01, 0xd8, 0xe2, 0x1e, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6d, 0x2e, 0x70, 0x6f, 0x6b, + 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0x42, 0x0a, 0x54, 0x79, 0x70, + 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x1f, 0x63, 0x6f, 0x73, 0x6d, 0x6f, + 0x73, 0x73, 0x64, 0x6b, 0x2e, 0x69, 0x6f, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x6f, 0x6b, 0x74, + 0x72, 0x6f, 0x6c, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6f, 0x66, 0xa2, 0x02, 0x03, 0x50, 0x50, 0x58, + 0xaa, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x2e, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0xca, 0x02, 0x0e, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, 0x6f, + 0x6f, 0x66, 0xe2, 0x02, 0x1a, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x5c, 0x50, 0x72, + 0x6f, 0x6f, 0x66, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, + 0x02, 0x0f, 0x50, 0x6f, 0x6b, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x3a, 0x3a, 0x50, 0x72, 0x6f, 0x6f, + 0x66, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1572,7 +1574,7 @@ var file_poktroll_proof_types_proto_goTypes = []interface{}{ var file_poktroll_proof_types_proto_depIdxs = []int32{ 5, // 0: poktroll.proof.Proof.session_header:type_name -> poktroll.session.SessionHeader 5, // 1: poktroll.proof.Claim.session_header:type_name -> poktroll.session.SessionHeader - 2, // 2: poktroll.proof.Claim.proof_status:type_name -> poktroll.proof.ClaimProofStatus + 2, // 2: poktroll.proof.Claim.proof_validation_status:type_name -> poktroll.proof.ClaimProofStatus 3, // [3:3] is the sub-list for method output_type 3, // [3:3] is the sub-list for method input_type 3, // [3:3] is the sub-list for extension type_name diff --git a/proto/poktroll/proof/event.proto b/proto/poktroll/proof/event.proto index f54231121..271a6c355 100644 --- a/proto/poktroll/proof/event.proto +++ b/proto/poktroll/proof/event.proto @@ -44,10 +44,13 @@ message EventProofUpdated { cosmos.base.v1beta1.Coin claimed_upokt = 6 [(gogoproto.jsontag) = "claimed_upokt"]; } -// Event emitted after a proof has been checked for validity. +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. message EventProofValidityChecked { poktroll.proof.Proof proof = 1 [(gogoproto.jsontag) = "proof"]; uint64 block_height = 2 [(gogoproto.jsontag) = "block_height"]; poktroll.proof.ClaimProofStatus proof_status = 3 [(gogoproto.jsontag) = "proof_status"]; + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") string reason = 4 [(gogoproto.jsontag) = "reason"]; } diff --git a/proto/poktroll/proof/types.proto b/proto/poktroll/proof/types.proto index e979621b6..c35b08fb8 100644 --- a/proto/poktroll/proof/types.proto +++ b/proto/poktroll/proof/types.proto @@ -24,14 +24,17 @@ message Proof { // Claim is the serialized object stored onchain for claims pending to be proven message Claim { + // Address of the supplier's operator that submitted this claim. string supplier_operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"]; // the address of the supplier's operator that submitted this claim - // The session header of the session that this claim is for. + + // Session header this claim is for. poktroll.session.SessionHeader session_header = 2; - // Root hash returned from smt.SMST#Root(). + + // Root hash from smt.SMST#Root(). bytes root_hash = 3; - // Claim proof status captures the status of the proof for this claim. - // WARNING: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath - ClaimProofStatus proof_status = 4; + + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ClaimProofStatus proof_validation_status = 4; } enum ProofRequirementReason { @@ -47,10 +50,10 @@ enum ClaimProofStage { EXPIRED = 3; } -// ClaimProofStatus defines the status of the proof for a claim. -// The default value is NOT_FOUND, whether the proof is required or not. +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement enum ClaimProofStatus { - NOT_FOUND = 0; - VALID = 1; + PENDING_VALIDATION = 0; + VALIDATED = 1; INVALID = 2; } \ No newline at end of file diff --git a/testutil/testtree/tree.go b/testutil/testtree/tree.go index 680a95011..6252926e2 100644 --- a/testutil/testtree/tree.go +++ b/testutil/testtree/tree.go @@ -152,6 +152,6 @@ func NewClaim( SupplierOperatorAddress: supplierOperatorAddr, SessionHeader: sessionHeader, RootHash: rootHash, - ProofStatus: prooftypes.ClaimProofStatus_NOT_FOUND, + ProofValidationStatus: prooftypes.ClaimProofStatus_PENDING_VALIDATION, } } diff --git a/x/proof/keeper/msg_server_submit_proof.go b/x/proof/keeper/msg_server_submit_proof.go index dadd4e977..30030a818 100644 --- a/x/proof/keeper/msg_server_submit_proof.go +++ b/x/proof/keeper/msg_server_submit_proof.go @@ -19,21 +19,18 @@ import ( sharedtypes "github.com/pokt-network/poktroll/x/shared/types" ) -// SubmitProof is the server handler to submit and store a proof onchain. -// A proof that's stored onchain is what leads to rewards (i.e. inflation) -// downstream, making this a critical part of the protocol. +// SubmitProof is the server message handler that stores a valid +// proof onchain, enabling downstream reward distribution. // -// Note that the validation of the proof is done in `EnsureValidProofSignaturesAndClosestPath`. -// However, preliminary checks are done in the handler to prevent sybil or DoS attacks on -// full nodes by submitting malformed proofs. +// IMPORTANT: Full proof validation occurs in EnsureValidProofSignaturesAndClosestPath. +// This handler performs preliminary validation to prevent sybil/DoS attacks. // -// We are playing a balance of security and efficiency here, where enough validation -// is done on proof submission, and exhaustive validation is done during the endblocker. +// There is a security & performance balance and tradeoff between the handler and end blocker: +// - Basic validation on submission (here) +// - Exhaustive validation in endblocker (EnsureValidProofSignaturesAndClosestPath) // -// The entity sending the SubmitProof messages does not necessarily need -// to correspond to the supplier signing the proof. For example, a single entity -// could (theoretically) batch multiple proofs (signed by the corresponding supplier) -// into one transaction to save on transaction fees. +// Note: Proof submitter may differ from supplier signer, allowing batched submissions +// to optimize transaction fees. func (k msgServer) SubmitProof( ctx context.Context, msg *types.MsgSubmitProof, @@ -85,7 +82,7 @@ func (k msgServer) SubmitProof( logger.Error(fmt.Sprintf("failed to ensure well-formed proof: %v", err)) return nil, status.Error(codes.FailedPrecondition, err.Error()) } - logger.Info("checked the proof is well-formed") + logger.Info("ensured the proof is well-formed") // Retrieve the claim associated with the proof. // The claim should ALWAYS exist since the proof validation in EnsureWellFormedProof diff --git a/x/proof/keeper/proof_validation.go b/x/proof/keeper/proof_validation.go index 897e3ed16..e4d53be2e 100644 --- a/x/proof/keeper/proof_validation.go +++ b/x/proof/keeper/proof_validation.go @@ -175,7 +175,7 @@ func (k Keeper) EnsureWellFormedProof(ctx context.Context, proof *types.Proof) e logger.Debug("successfully validated relay mining difficulty") // Retrieve the corresponding claim for the proof submitted - if err := k.validateClaimForProof(ctx, sessionHeader, supplierOperatorAddr); err != nil { + if err := k.validateSessionClaim(ctx, sessionHeader, supplierOperatorAddr); err != nil { return err } logger.Debug("successfully retrieved and validated claim") @@ -331,17 +331,16 @@ func (k Keeper) validateClosestPath( return nil } -// validateClaimForProof ensures that a claim corresponding to the given proof's -// session exists & has a matching supplier operator address and session header. -func (k Keeper) validateClaimForProof( +// validateSessionClaim ensures that the given session header and supplierOperatorAddress +// have a corresponding claim. +func (k Keeper) validateSessionClaim( ctx context.Context, sessionHeader *sessiontypes.SessionHeader, supplierOperatorAddr string, ) error { sessionId := sessionHeader.SessionId - // NB: no need to assert the testSessionId or supplier operator address as it is retrieved - // by respective values of the given proof. I.e., if the claim exists, then these - // values are guaranteed to match. + + // Retrieve the claim corresponding to the session ID and supplier operator address. foundClaim, found := k.GetClaim(ctx, sessionId, supplierOperatorAddr) if !found { return types.ErrProofClaimNotFound.Wrapf( @@ -352,41 +351,40 @@ func (k Keeper) validateClaimForProof( } claimSessionHeader := foundClaim.GetSessionHeader() - proofSessionHeader := sessionHeader // Ensure session start heights match. - if claimSessionHeader.GetSessionStartBlockHeight() != proofSessionHeader.GetSessionStartBlockHeight() { + if claimSessionHeader.GetSessionStartBlockHeight() != sessionHeader.GetSessionStartBlockHeight() { return types.ErrProofInvalidSessionStartHeight.Wrapf( "claim session start height %d does not match proof session start height %d", claimSessionHeader.GetSessionStartBlockHeight(), - proofSessionHeader.GetSessionStartBlockHeight(), + sessionHeader.GetSessionStartBlockHeight(), ) } // Ensure session end heights match. - if claimSessionHeader.GetSessionEndBlockHeight() != proofSessionHeader.GetSessionEndBlockHeight() { + if claimSessionHeader.GetSessionEndBlockHeight() != sessionHeader.GetSessionEndBlockHeight() { return types.ErrProofInvalidSessionEndHeight.Wrapf( "claim session end height %d does not match proof session end height %d", claimSessionHeader.GetSessionEndBlockHeight(), - proofSessionHeader.GetSessionEndBlockHeight(), + sessionHeader.GetSessionEndBlockHeight(), ) } // Ensure application addresses match. - if claimSessionHeader.GetApplicationAddress() != proofSessionHeader.GetApplicationAddress() { + if claimSessionHeader.GetApplicationAddress() != sessionHeader.GetApplicationAddress() { return types.ErrProofInvalidAddress.Wrapf( "claim application address %q does not match proof application address %q", claimSessionHeader.GetApplicationAddress(), - proofSessionHeader.GetApplicationAddress(), + sessionHeader.GetApplicationAddress(), ) } // Ensure service IDs match. - if claimSessionHeader.GetServiceId() != proofSessionHeader.GetServiceId() { + if claimSessionHeader.GetServiceId() != sessionHeader.GetServiceId() { return types.ErrProofInvalidService.Wrapf( "claim service ID %q does not match proof service ID %q", claimSessionHeader.GetServiceId(), - proofSessionHeader.GetServiceId(), + sessionHeader.GetServiceId(), ) } diff --git a/x/proof/keeper/validate_proofs.go b/x/proof/keeper/validate_proofs.go index 6ebce5af9..0e085aafe 100644 --- a/x/proof/keeper/validate_proofs.go +++ b/x/proof/keeper/validate_proofs.go @@ -11,9 +11,28 @@ import ( "github.com/pokt-network/poktroll/x/proof/types" ) -// numCPU is the number of CPU cores available on the machine. -// It is initialized in the init function to prevent runtime.NumCPU from being called -// multiple times in the ValidateSubmittedProofs function. +// proofValidationTaskCoordinator is a helper struct to coordinate parallel proof +// validation tasks. +type proofValidationTaskCoordinator struct { + // sem is a semaphore to limit the number of concurrent goroutines. + sem chan struct{} + + // wg is a wait group to wait for all goroutines to finish before returning. + wg *sync.WaitGroup + + // processedProofs is a map of supplier operator addresses to the session IDs + // whose proofs that have been processed. + processedProofs map[string][]string + + // numValidProofs and numInvalidProofs are counters to keep track of proof validation results. + numValidProofs, + numInvalidProofs uint64 + + // coordinatorMu protects the coordinator fields. + coordinatorMu *sync.Mutex +} + +// numCPU caches runtime.NumCPU() to avoid being retrieved on every ValidateSubmittedProofs call. var numCPU int func init() { @@ -21,18 +40,17 @@ func init() { numCPU = runtime.NumCPU() } -// ValidateSubmittedProofs concurrently validates block proofs. -// It marks their corresponding claims as valid or invalid based on the proof validation. -// It removes them from the store once they are processed. +// ValidateSubmittedProofs performs concurrent proof validation, updating claims' +// proof validation states and removing processed proofs from storage. func (k Keeper) ValidateSubmittedProofs(ctx sdk.Context) (numValidProofs, numInvalidProofs uint64, err error) { logger := k.Logger().With("method", "ValidateSubmittedProofs") logger.Info(fmt.Sprintf("Number of CPU cores used for parallel proof validation: %d\n", numCPU)) - // Iterate over proofs using an proofIterator to prevent memory issues from bulk fetching. + // Iterate over proofs using an iterator to prevent OOM issues caused by bulk fetching. proofIterator := k.GetAllProofsIterator(ctx) - coordinator := &proofValidationTaskCoordinator{ + proofValidationCoordinator := &proofValidationTaskCoordinator{ // Parallelize proof validation across CPU cores since they are independent from one another. // Use semaphores to limit concurrent goroutines and prevent memory issues. sem: make(chan struct{}, numCPU), @@ -48,23 +66,23 @@ func (k Keeper) ValidateSubmittedProofs(ctx sdk.Context) (numValidProofs, numInv // Acquire a semaphore to limit the number of goroutines. // This will block if the sem channel is full. - coordinator.sem <- struct{}{} + proofValidationCoordinator.sem <- struct{}{} // Increment the wait group to wait for proof validation to finish. - coordinator.wg.Add(1) + proofValidationCoordinator.wg.Add(1) - go k.validateProof(ctx, proofBz, coordinator) + go k.validateProof(ctx, proofBz, proofValidationCoordinator) } // Wait for all goroutines to finish before returning. - coordinator.wg.Wait() + proofValidationCoordinator.wg.Wait() // Close the proof iterator before deleting the processed proofs. proofIterator.Close() // Delete all the processed proofs from the store since they are no longer needed. logger.Info("removing processed proofs from the store") - for supplierOperatorAddr, processedProofs := range coordinator.processedProofs { + for supplierOperatorAddr, processedProofs := range proofValidationCoordinator.processedProofs { for _, sessionId := range processedProofs { k.RemoveProof(ctx, sessionId, supplierOperatorAddr) logger.Info(fmt.Sprintf( @@ -75,10 +93,10 @@ func (k Keeper) ValidateSubmittedProofs(ctx sdk.Context) (numValidProofs, numInv } } - return coordinator.numValidProofs, coordinator.numInvalidProofs, nil + return proofValidationCoordinator.numValidProofs, proofValidationCoordinator.numInvalidProofs, nil } -// validateProof validates a proof before removing it from the store. +// validateProof validates a proof submitted by a supplier. // It marks the corresponding claim as valid or invalid based on the proof validation. // It is meant to be called concurrently by multiple goroutines to parallelize // proof validation. @@ -101,6 +119,9 @@ func (k Keeper) validateProof( // proofBz is not expected to fail unmarshalling since it is should have // passed EnsureWellFormedProof validation in MsgSubmitProof handler. // Panic if it fails unmarshalling. + // If a failure occurs, it indicates either a bug in the code or data corruption. + // In either case, panicking is an appropriate response since both panics and + // returning an error would halt block production. k.cdc.MustUnmarshal(proofBz, &proof) sessionHeader := proof.GetSessionHeader() @@ -116,8 +137,8 @@ func (k Keeper) validateProof( // Retrieve the corresponding claim for the proof submitted so it can be // used in the proof validation below. - // EnsureWellFormedProof has already validated that the claim referenced by the - // proof exists and has a matching session header. + // EnsureWellFormedProof which is called in MsgSubmitProof handler has already validated + // that the claim referenced by the proof exists and has a matching session header. claim, claimFound := k.GetClaim(ctx, sessionHeader.GetSessionId(), supplierOperatorAddr) if !claimFound { // DEV_NOTE: This should never happen since EnsureWellFormedProof has already checked @@ -128,7 +149,7 @@ func (k Keeper) validateProof( logger.Debug("successfully retrieved claim") // Set the proof status to valid by default. - proofStatus := types.ClaimProofStatus_VALID + proofStatus := types.ClaimProofStatus_VALIDATED // Set the invalidity reason to an empty string by default. invalidProofCause := "" @@ -160,12 +181,12 @@ func (k Keeper) validateProof( coordinator.coordinatorMu.Lock() defer coordinator.coordinatorMu.Unlock() - // Update the claim to reflect its corresponding the proof validation result. + // Update the claim to reflect the validation result of the associated proof. // // It will be used later by the SettlePendingClaims routine to determine whether: // 1. The claim should be settled or not // 2. The corresponding supplier should be slashed or not - claim.ProofStatus = proofStatus + claim.ProofValidationStatus = proofStatus k.UpsertClaim(ctx, claim) // Collect the processed proofs info to delete them after the proofIterator is closed @@ -183,24 +204,3 @@ func (k Keeper) validateProof( coordinator.numValidProofs++ } } - -// proofValidationTaskCoordinator is a helper struct to coordinate parallel proof -// validation tasks. -type proofValidationTaskCoordinator struct { - // sem is a semaphore to limit the number of concurrent goroutines. - sem chan struct{} - - // wg is a wait group to wait for all goroutines to finish before returning. - wg *sync.WaitGroup - - // processedProofs is a map of supplier operator addresses to the session IDs - // of proofs that have been processed. - processedProofs map[string][]string - - // numValidProofs and numInvalidProofs are counters for the number of valid and invalid proofs. - numValidProofs, - numInvalidProofs uint64 - - // coordinatorMu protects the coordinator fields. - coordinatorMu *sync.Mutex -} diff --git a/x/proof/module/abci.go b/x/proof/module/abci.go index 88fc0762d..5c4f02d4b 100644 --- a/x/proof/module/abci.go +++ b/x/proof/module/abci.go @@ -17,7 +17,9 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (err error) { logger := k.Logger().With("method", "EndBlocker") - // Iterates through all proofs submitted in this block and removes invalid ones. + // Iterates through all proofs submitted in this block and: + // 1. Updates the proof validation status in the associated claim + // 2. Removes all processed proofs from onchain state numValidProofs, numInvalidProofs, err := k.ValidateSubmittedProofs(ctx) if err != nil { logger.Error(fmt.Sprintf("could not validate submitted proofs due to error %v", err)) @@ -25,7 +27,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (err error) { } logger.Info(fmt.Sprintf( - "validated %d proofs: %d valid, %d invalid", + "checked %d proofs: %d valid, %d invalid", numValidProofs+numInvalidProofs, numValidProofs, numInvalidProofs, diff --git a/x/proof/types/event.pb.go b/x/proof/types/event.pb.go index d71cea0bf..45873d3b6 100644 --- a/x/proof/types/event.pb.go +++ b/x/proof/types/event.pb.go @@ -330,12 +330,15 @@ func (m *EventProofUpdated) GetClaimedUpokt() *types.Coin { return nil } -// Event emitted after a proof has been checked for validity. +// Event emitted after a proof has been checked for validity in the proof module's +// EndBlocker. type EventProofValidityChecked struct { Proof *Proof `protobuf:"bytes,1,opt,name=proof,proto3" json:"proof"` BlockHeight uint64 `protobuf:"varint,2,opt,name=block_height,json=blockHeight,proto3" json:"block_height"` ProofStatus ClaimProofStatus `protobuf:"varint,3,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status"` - Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason"` + // reason is the string representation of the error that led to the proof being + // marked as invalid (e.g. "invalid closest merkle proof", "invalid relay request signature") + Reason string `protobuf:"bytes,4,opt,name=reason,proto3" json:"reason"` } func (m *EventProofValidityChecked) Reset() { *m = EventProofValidityChecked{} } @@ -385,7 +388,7 @@ func (m *EventProofValidityChecked) GetProofStatus() ClaimProofStatus { if m != nil { return m.ProofStatus } - return ClaimProofStatus_NOT_FOUND + return ClaimProofStatus_PENDING_VALIDATION } func (m *EventProofValidityChecked) GetReason() string { diff --git a/x/proof/types/types.pb.go b/x/proof/types/types.pb.go index f96db744a..dc594d9e0 100644 --- a/x/proof/types/types.pb.go +++ b/x/proof/types/types.pb.go @@ -84,26 +84,26 @@ func (ClaimProofStage) EnumDescriptor() ([]byte, []int) { return fileDescriptor_b75ef15dfd4d6998, []int{1} } -// ClaimProofStatus defines the status of the proof for a claim. -// The default value is NOT_FOUND, whether the proof is required or not. +// Status of proof validation for a claim +// Default is PENDING_VALIDATION regardless of proof requirement type ClaimProofStatus int32 const ( - ClaimProofStatus_NOT_FOUND ClaimProofStatus = 0 - ClaimProofStatus_VALID ClaimProofStatus = 1 - ClaimProofStatus_INVALID ClaimProofStatus = 2 + ClaimProofStatus_PENDING_VALIDATION ClaimProofStatus = 0 + ClaimProofStatus_VALIDATED ClaimProofStatus = 1 + ClaimProofStatus_INVALID ClaimProofStatus = 2 ) var ClaimProofStatus_name = map[int32]string{ - 0: "NOT_FOUND", - 1: "VALID", + 0: "PENDING_VALIDATION", + 1: "VALIDATED", 2: "INVALID", } var ClaimProofStatus_value = map[string]int32{ - "NOT_FOUND": 0, - "VALID": 1, - "INVALID": 2, + "PENDING_VALIDATION": 0, + "VALIDATED": 1, + "INVALID": 2, } func (x ClaimProofStatus) String() string { @@ -175,14 +175,14 @@ func (m *Proof) GetClosestMerkleProof() []byte { // Claim is the serialized object stored onchain for claims pending to be proven type Claim struct { + // Address of the supplier's operator that submitted this claim. SupplierOperatorAddress string `protobuf:"bytes,1,opt,name=supplier_operator_address,json=supplierOperatorAddress,proto3" json:"supplier_operator_address,omitempty"` - // The session header of the session that this claim is for. + // Session header this claim is for. SessionHeader *types.SessionHeader `protobuf:"bytes,2,opt,name=session_header,json=sessionHeader,proto3" json:"session_header,omitempty"` - // Root hash returned from smt.SMST#Root(). + // Root hash from smt.SMST#Root(). RootHash []byte `protobuf:"bytes,3,opt,name=root_hash,json=rootHash,proto3" json:"root_hash,omitempty"` - // Claim proof status captures the status of the proof for this claim. - // WARNING: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath - ProofStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_status,json=proofStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_status,omitempty"` + // Important: This field MUST only be set by proofKeeper#EnsureValidProofSignaturesAndClosestPath + ProofValidationStatus ClaimProofStatus `protobuf:"varint,4,opt,name=proof_validation_status,json=proofValidationStatus,proto3,enum=poktroll.proof.ClaimProofStatus" json:"proof_validation_status,omitempty"` } func (m *Claim) Reset() { *m = Claim{} } @@ -235,11 +235,11 @@ func (m *Claim) GetRootHash() []byte { return nil } -func (m *Claim) GetProofStatus() ClaimProofStatus { +func (m *Claim) GetProofValidationStatus() ClaimProofStatus { if m != nil { - return m.ProofStatus + return m.ProofValidationStatus } - return ClaimProofStatus_NOT_FOUND + return ClaimProofStatus_PENDING_VALIDATION } func init() { @@ -253,39 +253,41 @@ func init() { func init() { proto.RegisterFile("poktroll/proof/types.proto", fileDescriptor_b75ef15dfd4d6998) } var fileDescriptor_b75ef15dfd4d6998 = []byte{ - // 511 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x93, 0xcf, 0x6e, 0xd3, 0x40, - 0x10, 0xc6, 0xb3, 0x29, 0x2d, 0x64, 0xf3, 0x07, 0xb3, 0x8a, 0x20, 0x0d, 0xc8, 0x44, 0x3d, 0x45, - 0x91, 0xea, 0xa0, 0x72, 0xe2, 0x98, 0xc4, 0xae, 0x62, 0xc9, 0x8d, 0xc3, 0xda, 0xad, 0x10, 0x17, - 0xcb, 0x4d, 0x16, 0xdb, 0x8a, 0xed, 0x35, 0xbb, 0x1b, 0x01, 0x4f, 0xc0, 0x95, 0x87, 0xe1, 0x21, - 0x38, 0x56, 0x5c, 0xe8, 0x11, 0x25, 0x2f, 0x82, 0xbc, 0x76, 0x43, 0xca, 0x13, 0x70, 0xb2, 0x67, - 0x7f, 0x33, 0xdf, 0xcc, 0xb7, 0xda, 0x81, 0xdd, 0x8c, 0xae, 0x04, 0xa3, 0x71, 0x3c, 0xcc, 0x18, - 0xa5, 0x1f, 0x86, 0xe2, 0x4b, 0x46, 0xb8, 0x96, 0x31, 0x2a, 0x28, 0x6a, 0xdd, 0x31, 0x4d, 0xb2, - 0xee, 0xf1, 0x82, 0xf2, 0x84, 0x72, 0x4f, 0xd2, 0x61, 0x11, 0x14, 0xa9, 0xdd, 0x17, 0x3b, 0x19, - 0x4e, 0x38, 0x8f, 0x68, 0xba, 0x2f, 0xd4, 0x6d, 0x07, 0x34, 0xa0, 0x45, 0x55, 0xfe, 0x57, 0x9c, - 0x9e, 0xfc, 0x02, 0xf0, 0x70, 0x9e, 0x0b, 0x23, 0x17, 0x1e, 0xf3, 0x75, 0x96, 0xc5, 0x11, 0x61, - 0x1e, 0xcd, 0x08, 0xf3, 0x05, 0x65, 0x9e, 0xbf, 0x5c, 0x32, 0xc2, 0x79, 0x07, 0xf4, 0x40, 0xbf, - 0x36, 0xee, 0xfc, 0xfc, 0x7e, 0xda, 0x2e, 0x5b, 0x8e, 0x0a, 0xe2, 0x08, 0x16, 0xa5, 0x01, 0x7e, - 0x76, 0x57, 0x6a, 0x97, 0x95, 0x25, 0x46, 0xe7, 0xb0, 0x55, 0x0e, 0xe3, 0x85, 0xc4, 0x5f, 0x12, - 0xd6, 0xa9, 0xf6, 0x40, 0xbf, 0x7e, 0xf6, 0x52, 0xdb, 0xf9, 0x2a, 0xb9, 0xe6, 0x14, 0xdf, 0xa9, - 0x4c, 0xc3, 0x4d, 0xbe, 0x1f, 0xa2, 0x57, 0xb0, 0xbd, 0x88, 0x29, 0x27, 0x5c, 0x78, 0x09, 0x61, - 0xab, 0x98, 0x78, 0xf2, 0x3a, 0x3a, 0x07, 0x3d, 0xd0, 0x6f, 0x60, 0x54, 0xb2, 0x0b, 0x89, 0xa4, - 0x9f, 0x93, 0xaf, 0x55, 0x78, 0x38, 0x89, 0xfd, 0x28, 0xf9, 0xcf, 0x9d, 0x3d, 0x87, 0x35, 0x46, - 0xa9, 0xf0, 0x42, 0x9f, 0x87, 0xa5, 0x9d, 0x47, 0xf9, 0xc1, 0xd4, 0xe7, 0x21, 0x9a, 0xc0, 0x86, - 0xf4, 0xe9, 0x71, 0xe1, 0x8b, 0x35, 0xef, 0x3c, 0xe8, 0x81, 0x7e, 0xeb, 0xac, 0xa7, 0xdd, 0x7f, - 0x14, 0x9a, 0xf4, 0x29, 0x6d, 0x3b, 0x32, 0x0f, 0xd7, 0xb3, 0xbf, 0xc1, 0xc0, 0x82, 0x4f, 0x25, - 0xc3, 0xe4, 0xe3, 0x3a, 0x62, 0x24, 0x21, 0xa9, 0xc0, 0xc4, 0xe7, 0x34, 0x45, 0x0a, 0x6c, 0xcc, - 0x6c, 0xd7, 0xc3, 0xc6, 0xdb, 0x4b, 0x13, 0x1b, 0xba, 0x52, 0x41, 0x4f, 0x60, 0x73, 0x8e, 0xed, - 0xf1, 0x68, 0x6c, 0x5a, 0xa6, 0xe3, 0x9a, 0x13, 0x05, 0xa0, 0x26, 0xac, 0xb9, 0x53, 0x6c, 0x38, - 0x53, 0xdb, 0xd2, 0x95, 0xea, 0x40, 0x87, 0x8f, 0xef, 0xb5, 0x0b, 0x08, 0xaa, 0xc3, 0x87, 0x13, - 0x6b, 0x64, 0x5e, 0x48, 0x05, 0x08, 0x8f, 0xe6, 0xd8, 0xbe, 0x32, 0x66, 0x0a, 0xc8, 0x81, 0x63, - 0xb8, 0xae, 0x65, 0xe8, 0x4a, 0x35, 0x0f, 0x8c, 0x77, 0x73, 0xd9, 0xe7, 0x60, 0xf0, 0x06, 0x2a, - 0xff, 0x0e, 0x9d, 0x37, 0xca, 0xa7, 0x39, 0xb7, 0x2f, 0x67, 0xb9, 0x50, 0x0d, 0x1e, 0x5e, 0x8d, - 0x2c, 0x53, 0x2f, 0x74, 0xcc, 0x59, 0x11, 0x54, 0xc7, 0xd6, 0x8f, 0x8d, 0x0a, 0x6e, 0x36, 0x2a, - 0xb8, 0xdd, 0xa8, 0xe0, 0xf7, 0x46, 0x05, 0xdf, 0xb6, 0x6a, 0xe5, 0x66, 0xab, 0x56, 0x6e, 0xb7, - 0x6a, 0xe5, 0xbd, 0x16, 0x44, 0x22, 0x5c, 0x5f, 0x6b, 0x0b, 0x9a, 0x0c, 0xf3, 0x5b, 0x3a, 0x4d, - 0x89, 0xf8, 0x44, 0xd9, 0x6a, 0xb8, 0x5b, 0x8e, 0xcf, 0xfb, 0x5b, 0x76, 0x7d, 0x24, 0xf7, 0xe0, - 0xf5, 0x9f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd8, 0x7f, 0xdb, 0x75, 0x84, 0x03, 0x00, 0x00, + // 533 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x53, 0x5f, 0x6e, 0xda, 0x4e, + 0x10, 0x66, 0xc9, 0x2f, 0xf9, 0x95, 0x4d, 0xa0, 0xee, 0x8a, 0x26, 0x84, 0x56, 0x2e, 0xca, 0x13, + 0x42, 0x8a, 0xa9, 0xd2, 0x13, 0x00, 0x76, 0x8a, 0x25, 0xc7, 0xa6, 0x6b, 0x17, 0x45, 0x7d, 0xb1, + 0x36, 0xb0, 0x05, 0x0b, 0xe3, 0x75, 0x77, 0x97, 0xfe, 0xb9, 0x45, 0x0f, 0xd0, 0x63, 0xf4, 0x10, + 0x7d, 0x8c, 0xfa, 0xd2, 0x3c, 0x56, 0x70, 0x91, 0xca, 0x6b, 0x07, 0x91, 0x9e, 0xa0, 0x4f, 0xf6, + 0x7c, 0xdf, 0xcc, 0x37, 0xf3, 0x8d, 0x76, 0x60, 0x33, 0x65, 0x0b, 0xc9, 0x59, 0x1c, 0x77, 0x53, + 0xce, 0xd8, 0xfb, 0xae, 0xfc, 0x92, 0x52, 0x61, 0xa4, 0x9c, 0x49, 0x86, 0x6a, 0xf7, 0x9c, 0xa1, + 0xb8, 0xe6, 0xe9, 0x84, 0x89, 0x25, 0x13, 0xa1, 0x62, 0xbb, 0x79, 0x90, 0xa7, 0x36, 0x9f, 0x6f, + 0x65, 0x04, 0x15, 0x22, 0x62, 0xc9, 0xae, 0x50, 0xb3, 0x3e, 0x63, 0x33, 0x96, 0x57, 0x65, 0x7f, + 0x39, 0x7a, 0xf6, 0x0b, 0xc0, 0xfd, 0x51, 0x26, 0x8c, 0x02, 0x78, 0x2a, 0x56, 0x69, 0x1a, 0x47, + 0x94, 0x87, 0x2c, 0xa5, 0x9c, 0x48, 0xc6, 0x43, 0x32, 0x9d, 0x72, 0x2a, 0x44, 0x03, 0xb4, 0x40, + 0xbb, 0xd2, 0x6f, 0xfc, 0xfc, 0x7e, 0x5e, 0x2f, 0x5a, 0xf6, 0x72, 0xc6, 0x97, 0x3c, 0x4a, 0x66, + 0xf8, 0xe4, 0xbe, 0xd4, 0x2b, 0x2a, 0x0b, 0x1a, 0x5d, 0xc2, 0x5a, 0x31, 0x4c, 0x38, 0xa7, 0x64, + 0x4a, 0x79, 0xa3, 0xdc, 0x02, 0xed, 0xc3, 0x8b, 0x17, 0xc6, 0xd6, 0x57, 0xc1, 0x1b, 0x7e, 0xfe, + 0x1d, 0xaa, 0x34, 0x5c, 0x15, 0xbb, 0x21, 0x7a, 0x09, 0xeb, 0x93, 0x98, 0x09, 0x2a, 0x64, 0xb8, + 0xa4, 0x7c, 0x11, 0xd3, 0x50, 0xad, 0xa3, 0xb1, 0xd7, 0x02, 0xed, 0x23, 0x8c, 0x0a, 0xee, 0x4a, + 0x51, 0xca, 0xcf, 0xd9, 0xb7, 0x32, 0xdc, 0x1f, 0xc4, 0x24, 0x5a, 0xfe, 0xe3, 0xce, 0x9e, 0xc1, + 0x0a, 0x67, 0x4c, 0x86, 0x73, 0x22, 0xe6, 0x85, 0x9d, 0x47, 0x19, 0x30, 0x24, 0x62, 0x8e, 0xae, + 0xe1, 0x89, 0xf2, 0x19, 0x7e, 0x24, 0x71, 0x34, 0x25, 0x32, 0xeb, 0x26, 0x24, 0x91, 0x2b, 0xd1, + 0xf8, 0xaf, 0x05, 0xda, 0xb5, 0x8b, 0x96, 0xf1, 0xf0, 0x7d, 0x18, 0xca, 0xb2, 0xda, 0x80, 0xaf, + 0xf2, 0xf0, 0x53, 0x85, 0x8f, 0xb7, 0xf5, 0x39, 0xdc, 0x71, 0xe0, 0xb1, 0xca, 0xc2, 0xf4, 0xc3, + 0x2a, 0xe2, 0x74, 0x49, 0x13, 0x89, 0x29, 0x11, 0x2c, 0x41, 0x1a, 0x3c, 0x72, 0xbd, 0x20, 0xc4, + 0xd6, 0x9b, 0xb7, 0x36, 0xb6, 0x4c, 0xad, 0x84, 0x9e, 0xc0, 0xea, 0x08, 0x7b, 0xfd, 0x5e, 0xdf, + 0x76, 0x6c, 0x3f, 0xb0, 0x07, 0x1a, 0x40, 0x55, 0x58, 0x09, 0x86, 0xd8, 0xf2, 0x87, 0x9e, 0x63, + 0x6a, 0xe5, 0x8e, 0x09, 0x1f, 0x3f, 0x68, 0x3c, 0xa3, 0xe8, 0x10, 0xfe, 0x3f, 0x70, 0x7a, 0xf6, + 0x95, 0x52, 0x80, 0xf0, 0x60, 0x84, 0xbd, 0xb1, 0xe5, 0x6a, 0x20, 0x23, 0x7c, 0x2b, 0x08, 0x1c, + 0xcb, 0xd4, 0xca, 0x59, 0x60, 0x5d, 0x8f, 0x54, 0x9f, 0xbd, 0xce, 0x25, 0xd4, 0xfe, 0x1e, 0x1f, + 0x1d, 0x43, 0x34, 0xb2, 0x5c, 0xd3, 0x76, 0x5f, 0x87, 0xe3, 0x9e, 0x63, 0x9b, 0xbd, 0xc0, 0xf6, + 0x5c, 0xad, 0x94, 0x0d, 0x50, 0xc4, 0x96, 0x99, 0x8b, 0xda, 0xae, 0x02, 0xb4, 0x72, 0xdf, 0xf9, + 0xb1, 0xd6, 0xc1, 0xed, 0x5a, 0x07, 0x77, 0x6b, 0x1d, 0xfc, 0x5e, 0xeb, 0xe0, 0xeb, 0x46, 0x2f, + 0xdd, 0x6e, 0xf4, 0xd2, 0xdd, 0x46, 0x2f, 0xbd, 0x33, 0x66, 0x91, 0x9c, 0xaf, 0x6e, 0x8c, 0x09, + 0x5b, 0x76, 0xb3, 0xe5, 0x9d, 0x27, 0x54, 0x7e, 0x62, 0x7c, 0xd1, 0xdd, 0x9e, 0xcf, 0xe7, 0xdd, + 0x3b, 0xbc, 0x39, 0x50, 0x97, 0xf2, 0xea, 0x4f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x03, 0x4b, 0xbc, + 0x6b, 0xa6, 0x03, 0x00, 0x00, } func (m *Proof) Marshal() (dAtA []byte, err error) { @@ -357,8 +359,8 @@ func (m *Claim) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l - if m.ProofStatus != 0 { - i = encodeVarintTypes(dAtA, i, uint64(m.ProofStatus)) + if m.ProofValidationStatus != 0 { + i = encodeVarintTypes(dAtA, i, uint64(m.ProofValidationStatus)) i-- dAtA[i] = 0x20 } @@ -441,8 +443,8 @@ func (m *Claim) Size() (n int) { if l > 0 { n += 1 + l + sovTypes(uint64(l)) } - if m.ProofStatus != 0 { - n += 1 + sovTypes(uint64(m.ProofStatus)) + if m.ProofValidationStatus != 0 { + n += 1 + sovTypes(uint64(m.ProofValidationStatus)) } return n } @@ -738,9 +740,9 @@ func (m *Claim) Unmarshal(dAtA []byte) error { iNdEx = postIndex case 4: if wireType != 0 { - return fmt.Errorf("proto: wrong wireType = %d for field ProofStatus", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ProofValidationStatus", wireType) } - m.ProofStatus = 0 + m.ProofValidationStatus = 0 for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowTypes @@ -750,7 +752,7 @@ func (m *Claim) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - m.ProofStatus |= ClaimProofStatus(b&0x7F) << shift + m.ProofValidationStatus |= ClaimProofStatus(b&0x7F) << shift if b < 0x80 { break } diff --git a/x/tokenomics/keeper/settle_pending_claims.go b/x/tokenomics/keeper/settle_pending_claims.go index c8a8fae25..722d328d6 100644 --- a/x/tokenomics/keeper/settle_pending_claims.go +++ b/x/tokenomics/keeper/settle_pending_claims.go @@ -134,27 +134,25 @@ func (k Keeper) SettlePendingClaims(ctx cosmostypes.Context) ( proofIsRequired := proofRequirement != prooftypes.ProofRequirementReason_NOT_REQUIRED if proofIsRequired { - // The tokenomics end blocker, which calls SettlePendingClaims, is ALWAYS executed - // AFTER the proof submission window closes. In contrast, the proof end blocker, - // which handles proof validation, is ALWAYS executed WITHIN the proof submission - // window of the same session number. - // This ensures that proof validation is completed before claims settlement, - // as they occur at different block heights. + // IMPORTANT: Proof validation and claims settlement timing: + // - Proof validation (proof end blocker): Executes WITHIN proof submission window + // - Claims settlement (tokenomics end blocker): Executes AFTER window closes + // This ensures proofs are validated before claims are settled var expirationReason tokenomicstypes.ClaimExpirationReason - switch claim.ProofStatus { + switch claim.ProofValidationStatus { // If the proof is required and not found, the claim is expired. - case prooftypes.ClaimProofStatus_NOT_FOUND: + case prooftypes.ClaimProofStatus_PENDING_VALIDATION: expirationReason = tokenomicstypes.ClaimExpirationReason_PROOF_MISSING // If the proof is required and invalid, the claim is expired. case prooftypes.ClaimProofStatus_INVALID: expirationReason = tokenomicstypes.ClaimExpirationReason_PROOF_INVALID // If the proof is required and valid, the claim is settled. - case prooftypes.ClaimProofStatus_VALID: + case prooftypes.ClaimProofStatus_VALIDATED: expirationReason = tokenomicstypes.ClaimExpirationReason_EXPIRATION_REASON_UNSPECIFIED } - if claim.ProofStatus != prooftypes.ClaimProofStatus_VALID { + if claim.ProofValidationStatus != prooftypes.ClaimProofStatus_VALIDATED { // TODO_BETA(@red-0ne): Slash the supplier in proportion to their stake. // TODO_POST_MAINNET: Consider allowing suppliers to RemoveClaim via a new // message in case it was sent by accident From 307ff89562ac28fd7e382913faf94687b20c5c80 Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 29 Jan 2025 13:24:09 +0100 Subject: [PATCH 3/5] fix: Use fix smt verification concurrency --- pkg/crypto/protocol/proof_path.go | 28 ++++++++++++------------- x/proof/keeper/proof_validation.go | 10 ++++----- x/proof/keeper/proof_validation_test.go | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/pkg/crypto/protocol/proof_path.go b/pkg/crypto/protocol/proof_path.go index 61f7e23ce..1a48b40ee 100644 --- a/pkg/crypto/protocol/proof_path.go +++ b/pkg/crypto/protocol/proof_path.go @@ -6,20 +6,8 @@ import ( "github.com/pokt-network/smt" ) -// SMT specification used for the proof verification. -var ( - newHasher = sha256.New - SmtSpec smt.TrieSpec -) - -func init() { - // Use a spec that does not prehash values in the smst. This returns a nil value - // hasher for the proof verification in order to avoid hashing the value twice. - SmtSpec = smt.NewTrieSpec( - newHasher(), true, - smt.WithValueHasher(nil), - ) -} +// newHasher is the hash function used by the SMT specification. +var newHasher = sha256.New // GetPathForProof computes the path to be used for proof validation by hashing // the block hash and session id. @@ -31,3 +19,15 @@ func GetPathForProof(blockHash []byte, sessionId string) []byte { return hasher.Sum(nil) } + +// NewSMTSpec returns the SMT specification used for the proof verification. +// It uses a new hasher at every call to avoid concurrency issues that could be +// caused by a shared hasher. +func NewSMTSpec() *smt.TrieSpec { + trieSpec := smt.NewTrieSpec( + newHasher(), true, + smt.WithValueHasher(nil), + ) + + return &trieSpec +} diff --git a/x/proof/keeper/proof_validation.go b/x/proof/keeper/proof_validation.go index e4d53be2e..bf55d2e3c 100644 --- a/x/proof/keeper/proof_validation.go +++ b/x/proof/keeper/proof_validation.go @@ -106,14 +106,14 @@ func (k Keeper) EnsureWellFormedProof(ctx context.Context, proof *types.Proof) e } // SparseCompactMerkeClosestProof does not implement GetValueHash, so we need to decompact it. - sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, &protocol.SmtSpec) + sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) if err != nil { logger.Error(fmt.Sprintf("failed to decompact sparse merkle closest proof due to error: %v", err)) return types.ErrProofInvalidProof.Wrapf("failed to decompact sparse erkle closest proof: %s", err) } // Get the relay request and response from the proof.GetClosestMerkleProof. - relayBz := sparseMerkleClosestProof.GetValueHash(&protocol.SmtSpec) + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) relay := &servicetypes.Relay{} if err = k.cdc.Unmarshal(relayBz, relay); err != nil { logger.Error(fmt.Sprintf("failed to unmarshal relay due to error: %v", err)) @@ -231,14 +231,14 @@ func (k Keeper) EnsureValidProofSignaturesAndClosestPath( // SparseCompactMerkeClosestProof was intentionally compacted to reduce its onchain state size // so it must be decompacted rather than just retrieving the value via GetValueHash (not implemented). - sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, &protocol.SmtSpec) + sparseMerkleClosestProof, err := smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) if err != nil { logger.Error(fmt.Sprintf("failed to decompact sparse merkle closest proof due to error: %v", err)) return types.ErrProofInvalidProof.Wrapf("failed to decompact sparse merkle closest proof: %s", err) } // Get the relay request and response from the proof.GetClosestMerkleProof. - relayBz := sparseMerkleClosestProof.GetValueHash(&protocol.SmtSpec) + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) relay := &servicetypes.Relay{} if err = k.cdc.Unmarshal(relayBz, relay); err != nil { logger.Error(fmt.Sprintf("failed to unmarshal relay due to error: %v", err)) @@ -449,7 +449,7 @@ func verifyClosestProof( proof *smt.SparseMerkleClosestProof, claimRootHash []byte, ) error { - valid, err := smt.VerifyClosestProof(proof, claimRootHash, &protocol.SmtSpec) + valid, err := smt.VerifyClosestProof(proof, claimRootHash, protocol.NewSMTSpec()) if err != nil { return err } diff --git a/x/proof/keeper/proof_validation_test.go b/x/proof/keeper/proof_validation_test.go index 349dcd59c..f2701db84 100644 --- a/x/proof/keeper/proof_validation_test.go +++ b/x/proof/keeper/proof_validation_test.go @@ -611,10 +611,10 @@ func TestEnsureValidProof_Error(t *testing.T) { err = sparseCompactMerkleClosestProof.Unmarshal(proof.ClosestMerkleProof) require.NoError(t, err) var sparseMerkleClosestProof *smt.SparseMerkleClosestProof - sparseMerkleClosestProof, err = smt.DecompactClosestProof(sparseCompactMerkleClosestProof, &protocol.SmtSpec) + sparseMerkleClosestProof, err = smt.DecompactClosestProof(sparseCompactMerkleClosestProof, protocol.NewSMTSpec()) require.NoError(t, err) - relayBz := sparseMerkleClosestProof.GetValueHash(&protocol.SmtSpec) + relayBz := sparseMerkleClosestProof.GetValueHash(protocol.NewSMTSpec()) relayHashArr := protocol.GetRelayHashFromBytes(relayBz) relayHash := relayHashArr[:] From ba4df79b9117dec092e59feeb7e03146be4c7afe Mon Sep 17 00:00:00 2001 From: Redouane Lakrache Date: Wed, 29 Jan 2025 13:59:49 +0100 Subject: [PATCH 4/5] Empty commit From 3345bd2901c058c12b38b4c11259c7a358958cc3 Mon Sep 17 00:00:00 2001 From: forcedebug <167591285+forcedebug@users.noreply.github.com> Date: Thu, 30 Jan 2025 01:49:11 +0800 Subject: [PATCH 5/5] chore: fix some function names in comment (#1019) fix some function names in comment --- e2e/tests/node.go | 2 +- e2e/tests/reset_params_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tests/node.go b/e2e/tests/node.go index 6620c995e..d49970d8c 100644 --- a/e2e/tests/node.go +++ b/e2e/tests/node.go @@ -187,7 +187,7 @@ func (p *pocketdBin) runPocketCmd(args ...string) (*commandResult, error) { return r, err } -// runCurlPostCmd is a helper to run a command using the local pocketd binary with the flags provided +// runCurlCmd is a helper to run a command using the local pocketd binary with the flags provided func (p *pocketdBin) runCurlCmd(rpcBaseURL, service, method, path, appAddr, data string, args ...string) (*commandResult, error) { rpcUrl, err := url.Parse(rpcBaseURL) if err != nil { diff --git a/e2e/tests/reset_params_test.go b/e2e/tests/reset_params_test.go index 404ecd176..3b0c0ab1d 100644 --- a/e2e/tests/reset_params_test.go +++ b/e2e/tests/reset_params_test.go @@ -28,7 +28,7 @@ func (s *suite) resetAllModuleParamsToDefaults() { s.sendAuthzExecTx(s.granteeName, resetTxJSONFile.Name()) } -// allMoudlesMsgUpdateParamsToDefaultsAny returns a slice of Any messages, each corresponding +// allModulesMsgUpdateParamsToDefaultsAny returns a slice of Any messages, each corresponding // to a MsgUpdateParams for a module, populated with the respective default values. func (s *suite) allModulesMsgUpdateParamsToDefaultsAny() []*codectypes.Any { s.Helper()