Constant PLATFORM_V15
pub const PLATFORM_V15: PlatformVersion;Expand description
Introduced as the activation gate for the consensus changes of the 4.3 line. Functionally identical to v14 at introduction: the same component version structs, no behavior change. Each change that needs this gate lands in its own follow-up and bumps the component table it consumes here; keeping v15 == v14 until then lets mixed-version validators agree.
v15 hosts these consensus changes:
-
Chain locks signed by quorums Platform does not hold yet: a block proposal’s chain lock is checked against the chain lock quorums Platform fetched at its last committed core height. When a quorum was mined after that height, inside the same DKG interval, or when the signing height lies between the two stored quorum sets after a jump of the core height, the chain lock is signed by quorums Platform does not hold, and
verify_chain_lock_locally0 rejected it although it was valid, failing rounds until Core produced a chain lock Platform could verify or one signed past the DKG interval.verify_chain_lock_locally1 (DRIVE_ABCI_METHOD_VERSIONS_V11) rejects locally only when Platform holds exactly the quorums active at the signing height, using Dash Core’s DKG mining schedule (core_chain_lock.dkg_mining_schedules), and leaves the other chain locks to Core.verify_chain_lock_through_core1 has Core’sverifychainlockcheck the signature of every chain lock left to Core beforesubmitchainlock, which skips that check for a height Core already has a chain lock at or above, and reports a failure as Core’s verdict. So v15 accepts valid chain locks that v14 rejected, and rejects forged ones that v14 left tosubmitchainlock’s early return. Protocol v14 and earlier keepverify_chain_lock_locally0 andverify_chain_lock_through_core0, so the blocks committed under them replay with the same verdicts. -
Proofs of possession of the keys an identity update adds: the identity’s signature over an identity update does not cover the signatures of the keys it adds. The identity update
advanced_structure1 (DRIVE_ABCI_VALIDATION_VERSIONS_V11) refuses, without a fee and without using the identity’s nonce, an update whose added key’s proof of possession does not verify (a key whose public key data does not decode fails it too), where 0 charged it; a revision mismatch is still charged. Protocol v14 and earlier keepadvanced_structure0, so the blocks committed under them replay with the same results. check_tx verifies these proofs at every protocol version, which decides mempool admission only. -
DPNS v3 checks a name’s create with keywords:
SYSTEM_DATA_CONTRACT_VERSIONS_V4selects DPNS contract v3, loaded at genesis (which still inserts thedashtop-level domain). ItsdomaingeneratesnormalizedLabelandnormalizedParentDomainNamewithsys.stringTransformations.homographSafeASCII(a value sent that differs isDocumentPropertyNotGeneratedError, 10424). ItscreatorRefersTofinds the creator’s ownpreorderof the name, throughfindBy$ownerIdandnameHash(the sha256d of the normalized label,"."and the normalized parent), from an earlier block (minimumAgeBlocks: 1), and deletes it (consume, beside thewhereentry$ownerId); not found is 40120, too young 40142. ItschooseFirstrefuses the create while another identity holds an unexpired preorder of the name from an earlier block that holds, atownerNameHash, the sha256d of its own owner’s id and the name (ReferencedDocumentPrecededError, 40149), and the found preorder must hold that hash with the creator’s id (else 40120). So a preorder copied from a pending one counts for nobody, and an identity that learns a name from a pending reveal and preorders it itself comes after the revealer. A preorder carries no salt: it holds both hashes, is unique per owner and name (ownerAndNameHashover$ownerIdandnameHash, replacingsaltedHash), is indexed bynameHashand creation height (nameHashAndHeight) and lives an hour (ttl3600, so it refunds nothing when consumed). A name holds at most 1,000 preorders, the most achooseFirstreads (max_choose_first_candidates): the preorder’satMostAThousandPerNamerule counts them through a countablenameHashindex (note 4), so a reveal always reads every preorder before its own and no copy can hide an older valid one; a preorder past it is refused (10422). ThedomainkeepspreorderSaltdeclared, transient and no longer required, so domains written under v1 and v2 decode. The rulerecordsIdentityIsOwner($transferredAtequal to$createdAtimpliesrecords.identityequal to$ownerId) holds a new name’s identity record to its owner (10422); a transfer or a purchase in a later block no longer reads it, and one in the block that created the name is refused. ThedomainsetscanBeDeleted: false; its property positions, transient list and stored encoding are v2’s.transition_to_version_15re-stores DPNS throughDrive::apply_contract_rebuilding_document_types: every preorder made before the upgrade is deleted, unrefunded, and thepreordertype is rebuilt as a contract update creates a type it adds, the layout a chain born at this version has.DRIVE_ABCI_VALIDATION_VERSIONS_V11selectscreate_domain_data_trigger2, which keeps only the parent domain checks: a top-level domain only by the contract owner, the parent present, no subdomains under a name, and the parent’s subdomain rule. The data trigger bindings stay at 2: theirdomainReplace and Delete rejects are never reached, asdocumentsMutableandcanBeDeletedfalse refuse both first (10404). -
countOfandsumOfmatch byte array keys:CONTRACT_VERSIONS_V7selectsparse_property_constraints1, whose grammar binds a filter key to a byte array property of the document written (or deleted),{ "nameHash": "nameHash" }, and reads that property as a byte array, and whose registration check admits a byte array key of the counted type bound to a byte array property (never a constant,$ownerIdor$id). The count or sum tree holds the key asserialize_value_for_keywrites it, so consensus reads the total as it reads any other.parse_property_constraints0 (protocol version 14) reads such a binding as an integer and refuses it. -
Tradeable tokens:
TokenTradeMode::Tradeable(TOKEN_MARKETPLACE_INITIAL_PROTOCOL_VERSION) lets a token’s holders list it and make offers for it. Before this version a contract whose token is tradeable, and aTokenConfigUpdatethat makes a token tradeable, are refused unpaid as not active (StateTransitionNotActiveError, 10603), the refusal older software gives by failing to decode the mode. A tradeable token must be transferable (NonTransferableTokenTradeableError, 10281): contract create and update refuse it unpaid, and the batchadvanced_structure2 (DRIVE_ABCI_VALIDATION_VERSIONS_V11) checks the trade mode an update proposes against the contract the action carries, charged, so check_tx refuses the update too. Protocol v14 and earlier keep the batchadvanced_structure1. -
Documents checked natively:
CONTRACT_VERSIONS_V7selectsvalidate_document2, which checks a document against its type’s typed validation schema (document_type::schema::validation_schema, built byvalidation_schema0) instead of thejsonschemacrate, reaching the same verdicts and error codes but for one rule of its own: in auniqueItemslist,0.0and-0.0are one value however long the list. A document type whose schema the validation schema does not represent has its documents refused (InvalidContractStructure): no document is checked through thejsonschemacrate. Protocol v14 and earlier keepvalidate_document1. -
Schemas checked natively at registration:
CONTRACT_VERSIONS_V7selectscheck_document_type_schema1: full validation checks a document type’s schema with the rules of document meta-schema v3 in Platform’s own code instead of through thejsonschemacrate, refusing with the sameJsonSchemaError. It holds an index property name to 255 bytes, where the meta-schema admitted 256 characters, treats0.0and-0.0as one value in a list that must be unique, such as anenum’s members, however long the list, as the document check of note 6 does, and refuses a document type the typed validation schema does not represent (InvalidContractStructure), so every type registered from this version has its documents checked natively (note 6). The parser is generation 3 at both versions, and loading a stored contract runs no schema check. Protocol v14 and earlier keepcheck_document_type_schema0. -
Contracts stored compiled:
CONTRACT_VERSIONS_V7selectscontract_storage_serialization_version2: Drive stores a contract it creates or updates in format version 2, its schemas with each document type compiled (DocumentTypeInSerializationFormat0), and reads such a contract back without parsing its schemas, so it keeps the meaning it was compiled with. State transitions, unproved query responses and JSON keep format version 1 (contract_serialization_version), and a transition carrying format version 2 is refused while decoding at every version. The 65,000-byte cap still applies to the contract’s format version 1 bytes; the compiled bytes, about 1.8 times as many, are paid by the byte, and a contract read pays its larger size.DRIVE_VERSION_V10selectsapply_contract_with_serialization1, which writes nothing when a contract’s format version 1 bytes match the stored one’s. Contracts stored before this version stay in their format until their next write, a contract update or a token configuration update, which re-stores them compiled: its sender pays the growth, for a token configuration update the group member whose action closes it, not the owner. A chain started at this version stores every system contract compiled at genesis, while a chain upgraded to it keeps them in the format they were stored in, so a transition reading one pays more on the first. A proof of a contract stored compiled carries the compiled bytes, about 1.8 times as large, and clients need a decoder that reads format version 2 to verify it. A contract compiled takes at mostmax_compiled_contract_size(1 MiB): registration and update refuse a contract over it, and a token configuration update one it would take over it (DataContractCompiledMaxSizeExceededError, 10282). check_tx and recheck, which run no state validation, hold a contract update to it throughDRIVE_ABCI_VALIDATION_VERSIONS_V11’stransform_into_action1, with the contract’s time fields at their widest: a bound on what a block measures. Protocol v14 and earlier keep format version 1 (0 before v9) andapply_contract_with_serialization0. -
Token configuration updates on read-only contracts: a token’s configuration is part of its contract, so a performed
TokenConfigUpdatestores the contract again, which Drive refuses for a read-only contract. No validation step looked at the flag, so such an update passed validation and check_tx and failed only when its block was executed, which leaves it out of the block. The batchadvanced_structure2 (DRIVE_ABCI_VALIDATION_VERSIONS_V11) refuses an update of a token on a read-only contract, performed or a group member’s vote, withDataContractIsReadonlyError(40001), charged, so check_tx refuses it too. Protocol v14 and earlier keep the batchadvanced_structure1. -
Yes/no vote polls: a second kind of masternode vote poll, which asks “should this happen?” and passes on a supermajority of yes over yes plus no with a minimum of voting power cast. A poll is identified by its purpose (a decision proposal’s document id): its id is derived from the purpose alone, a vote names the poll by that id, and the rule is kept in the poll’s stored info. A minimum given as a share of the network’s voting power leaves PoSe-banned masternodes out of the total. A masternode vote naming a yes/no poll is active from this version (
StateTransition::active_version_range); the polls live under the votes tree’s decisions branch, which genesis (create_initial_state_structure4 behind>= YES_NO_VOTE_POLL_INITIAL_PROTOCOL_VERSION, 15) andtransition_to_version_15create. Masternode votetransform_into_action1 (DRIVE_ABCI_VALIDATION_VERSIONS_V11) looks up the previous answer, andDRIVE_VERSION_V10registers and sweeps the votes. Opening a yes/no poll (Drive::open_yes_no_vote_poll; everyyes_nodrive method isSome(0)) is active from this version, for an end date at mostmax_yes_no_vote_poll_duration_ms(four weeks, aSystemLimitsfield read only by the opener) after the opening block, and its end date entry goes throughadd_vote_poll_end_date_query_operations1, which adds only the entry when the batch already queues the end date’s tree with other storage flags. Every other yes/no method is active from this version too andNone(not active) in every earlier table: the poll’s id and rules (VOTING_VERSION_V3), the end-of-block tally, record and clean-up (DRIVE_ABCI_METHOD_VERSIONS_V11voting), removing finished polls from the end date index (remove_vote_poll_end_date_query_operations) and the proof verifiers (DRIVE_VERIFY_METHOD_VERSIONS_V4). Nothing calls the opener yet, so at this version every yes/no vote is refused for want of a poll. -
A consume deletes what its lookup read: document reference validation 1 (
DRIVE_ABCI_VALIDATION_VERSIONS_V11) reads the commitment that therefersTolookup of a reference declaringconsumefinds with its stored element’s storage flags (query_documents_with_flags), and keeps that read in theConsumedDocument. Any other lookup reads as document reference validation 0’s does. The create conversion 1 (DRIVE_STATE_TRANSITION_METHOD_VERSIONS_V5, whichDRIVE_VERSION_V10selects) deletes the document from it (Drive::force_delete_read_document_for_contract_operations, the force delete’s operations less its read), where conversion 0 deletes it by id and bills a second read. A consume costs one document read less: a DPNS v3 name create’s processing fee drops by 10,660 credits. Storage fees and refunds are unchanged. Protocol v14 and earlier keep document reference validation 0 and the create conversion 0.