From mboxrd@z Thu Jan 1 00:00:00 1970 Delivery-date: Thu, 16 Apr 2026 12:44:55 -0700 Received: from mail-oa1-f56.google.com ([209.85.160.56]) by mail.fairlystable.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.94.2) (envelope-from ) id 1wDSdy-00031I-3n for bitcoindev@gnusha.org; Thu, 16 Apr 2026 12:44:55 -0700 Received: by mail-oa1-f56.google.com with SMTP id 586e51a60fabf-4240a9f9375sf8236847fac.1 for ; Thu, 16 Apr 2026 12:44:53 -0700 (PDT) ARC-Seal: i=2; a=rsa-sha256; t=1776368688; cv=pass; d=google.com; s=arc-20240605; b=YVg/jycnKZ7JTWYqkyWYkhlN1V1uCsw0w1mRYrOnSVCUh6nxTf0XAswBIAV9+9qDDx TqCpeYFWULGmy5NQqdcOUIcrbYHDvZNJibMAhvZ6+MtQUvN+iABu1a2xVbvFFX1k3YYw 48pajSzx5KO0BiAO8xAVAdSm9Dmrl4ymlKo/84KiXfaYHLTZqgT+tJvzM6kcOmXJjIPG CMQH5NE+cTTlf/0HAOHrYtHz5BxFA14phX0OQZNr39AJQS8WdIEmBo/r3jQ2aPCYhY+C mrz2wU8Y4HHivuawoif64UAAN+iSoumIW5rqwWR+z6C1IUWpXIdbOAeUrkanPZnRlZqv pkJA== ARC-Message-Signature: i=2; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to:content-transfer-encoding :mime-version:feedback-id:references:in-reply-to:message-id:subject :cc:from:to:date:dkim-signature; bh=7TKlowa0PzFXZw0yKioyaGEy1GrhIyZkOnioUyoCHYE=; fh=MRY1nK76oGozkvNe/VTPb6qYT45NxX9EdQPna6txmLM=; b=e1i4suUGe3HK0Xbuipdkeoj7FgIKvouaEFjm67DgSdwCFMNDNVSBtj5f9IWCnbTlg4 UhUgCo+Xscj//EH3G9FcijNscR65ni4ilMRl8n3nDgPDUxMDDQl/SthqWFl6aja784Gk dipJhc5nEzwB55tVDqFCY5TAG0KbdtIa88fTxw4SBOPYlIVYOp/mxfDUJl+kUn2KNuMi i0BeqxEIN4dRx5d92NOhk6S+xxPLqFIub0q8Bg3Z3zLoTFPOJQSuB5uBP8MZN+30TU+e /9SzS3P0IyqBXkQTRVT88iP/U2KLor/qkFA/AKPSUGN1bRiNFPTWXjpE7IfQLskpNdfJ FMzA==; darn=gnusha.org ARC-Authentication-Results: i=2; gmr-mx.google.com; dkim=pass header.i=@hornetnode.org header.s=protonmail2 header.b=sid8zHFO; spf=pass (google.com: domain of toby@hornetnode.org designates 109.224.244.117 as permitted sender) smtp.mailfrom=toby@hornetnode.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=hornetnode.org DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlegroups.com; s=20251104; t=1776368688; x=1776973488; darn=gnusha.org; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender :content-transfer-encoding:mime-version:feedback-id:references :in-reply-to:message-id:subject:cc:from:to:date:from:to:cc:subject :date:message-id:reply-to; bh=7TKlowa0PzFXZw0yKioyaGEy1GrhIyZkOnioUyoCHYE=; b=WSOyF/fh8y/vUEHROwh3RXawQZ4dLyUB6LauNpTFyF+eOEXPpOJ8npZL+Lus6KX8pW EU1e16ZcUG3u1ucgN7IXC/sNJg824oIkSZdLFxGwDu8OQwiM7DKt0msBbQS7NxfK3vV/ TUbVHWthqf64W3GxjyU6u9ULnJEJ35YVBBteHxu4+eVdcZIzl6mywLLXad4koyyoV+Zu 4FPddrYQThsULk7Bt9Tj5hJ4/fKGy6jNMXeonuiuTvWz3HJ9CcbHHUHizAqECfem6TRp 6jH9XSb/5gqkgvOYHy0eeV3oBG7HB3S3cZOXj8dmym45kwlj1nAzaD1NbqPUPLwOScEK WljQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776368688; x=1776973488; h=list-unsubscribe:list-subscribe:list-archive:list-help:list-post :list-id:mailing-list:precedence:reply-to :x-original-authentication-results:x-original-sender :content-transfer-encoding:mime-version:feedback-id:references :in-reply-to:message-id:subject:cc:from:to:date:x-beenthere :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=7TKlowa0PzFXZw0yKioyaGEy1GrhIyZkOnioUyoCHYE=; b=bfvwju5pr1/SZw5TAmG7+PocN2YKZTPJWrUPZ02baGgwRcmJvsGbZ1q1W6bo4qQNcL r3+SOm4KH2T7L0Lv0uvjvljFaZ7tCNRg0zE52LGodldYvdt6rJDMCKfL/TPFusd90WjR FPlMhgQ8UeFeNcXVzWcxwp7BPvHLu6XEF/Dz1mqIV6e7KKeySxgQ5jaQpFHGKNGywd2l eRtL3ppIPbuoU/KHKKpkY4XnUerAshCgpg+siLk8dbqVSc6giRDYTriuIv1nHKI1WA/t fqD59R0samW3cB55wmoWegjde05ZyL02HliksrXId76/4ct5wF9GW5KF02wLlbFi577/ O/mg== X-Forwarded-Encrypted: i=2; AFNElJ+kXjzMOtbfL9Ivxd7Gx/aDzRoxmsjzhQXCp+3YTGa8VpuIm4mFczD/WDboFYxvT8aM7SGCQXfjGZUu@gnusha.org X-Gm-Message-State: AOJu0YxFB1if0LOKyx0BRVShKbOHxWijmeK/wDugfvpmUFfVNqHBQ6PD UaxTSdc23xAYr3gFMwtIdOncprLIxcT3J8TTt4nwwWg1fRN07yiqHuSt X-Received: by 2002:a05:6871:758b:b0:417:258b:4416 with SMTP id 586e51a60fabf-4288f0c5a75mr542769fac.3.1776368687539; Thu, 16 Apr 2026 12:44:47 -0700 (PDT) X-BeenThere: bitcoindev@googlegroups.com; h="AYAyTiJIzjpMU5go0eePGY+e/FuU2ySTyP9iQEixuDEfEb7EPQ==" Received: by 2002:a05:6870:9f0e:b0:41c:583a:b5c with SMTP id 586e51a60fabf-4280c55901fls690661fac.2.-pod-prod-07-us; Thu, 16 Apr 2026 12:44:43 -0700 (PDT) X-Received: by 2002:a05:6808:180b:b0:467:bfa:bd9b with SMTP id 5614622812f47-4799a233197mr196628b6e.21.1776368683215; Thu, 16 Apr 2026 12:44:43 -0700 (PDT) Received: by 2002:a05:620a:a0dc:20b0:8b2:e5d4:9264 with SMTP id af79cd13be357-8e659d6f840ms85a; Thu, 16 Apr 2026 11:41:39 -0700 (PDT) X-Received: by 2002:a05:620a:4151:b0:8db:7315:706c with SMTP id af79cd13be357-8e74c39fad4mr83317685a.59.1776364898531; Thu, 16 Apr 2026 11:41:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1776364898; cv=none; d=google.com; s=arc-20240605; b=I3MzQJwxi3+hcD7X0vwVYjODWc2x17vyf6eWh/VBIBijRHczln6v+LTwVQzniuc/uH s5LicHPmx02II1vdbCPe7H+XoAqe+zsoE+ELUs4if71h47V5VzhA9QTmfVwHDCPnzdfT bijH1ops5ZY7o8UZ1fx3lSLku1C3rOz09BwRfChvMmRCppc5u36LkHG3YBeuFpEX+YMv d9+5oVRXuLWWPhsrBniPcp+vyCCBwksg9mhUPu2Rog87My3mJt2nqH4jKRVSoRWrgaog jl3VJMfEtpFbwsG+m5WHHU43rNb9XIPnRpdYWzgCmKT5GANCOKXfkB3hgPROXDKJPMjx ObSg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:mime-version:feedback-id:references :in-reply-to:message-id:subject:cc:from:to:date:dkim-signature; bh=kyvlCrKrZUe2N9hBhFOSCSJfvDKjAF8A/WezmU6V0vI=; fh=vfPP9iqpsn+L6IpDObIz3VSXaC72IQB5ATjaiPEmUGA=; b=AnWTgUczR9xbyGsr3GiXFZybiYbkxiTJKtYcGKlRQizyh/tc3aKKiiIDdPFNh+T5so 2m9Db6dI7SmD/7BJhS0j3un69LPcIwZoqhu1Z421xcg6sUnBi8lUeNZkD6ETy5SdMubA TusBZViZffs4uodATsVWd85YHmGUNI3oOU721NO51TF/M3x8sBgu2L+qqCrQmNnc8+bL Y10f6au4ygWen4S9phgcgvGmF+NyJuCymkYXFlgvHeLA0PJ5EB0pD6h8oyZ0Lad2TjWp +tBn7miRuTzdkRdeYjuZTLJNIX6Xtck1ipdMewt7TwU4AiOq0U7s2ECnWDt9Mw342mZX rwsw==; dara=google.com ARC-Authentication-Results: i=1; gmr-mx.google.com; dkim=pass header.i=@hornetnode.org header.s=protonmail2 header.b=sid8zHFO; spf=pass (google.com: domain of toby@hornetnode.org designates 109.224.244.117 as permitted sender) smtp.mailfrom=toby@hornetnode.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=hornetnode.org Received: from mail-244117.protonmail.ch (mail-244117.protonmail.ch. [109.224.244.117]) by gmr-mx.google.com with ESMTPS id af79cd13be357-8e4f243e067si17326385a.4.2026.04.16.11.41.38 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 16 Apr 2026 11:41:38 -0700 (PDT) Received-SPF: pass (google.com: domain of toby@hornetnode.org designates 109.224.244.117 as permitted sender) client-ip=109.224.244.117; Date: Thu, 16 Apr 2026 18:41:31 +0000 To: eric@voskuil.org From: "'Toby Sharp' via Bitcoin Development Mailing List" Cc: 'Bitcoin Development Mailing List' Subject: RE: [bitcoindev] Hornet Update: A declarative executable specification of Bitcoin consensus rules Message-ID: In-Reply-To: <006501dccd36$ea035fd0$be0a1f70$@voskuil.org> References: <4cd864f3-96dd-4058-bfcd-b1bbf6cfa269n@googlegroups.com> <006501dccd36$ea035fd0$be0a1f70$@voskuil.org> Feedback-ID: 160430243:user:proton X-Pm-Message-ID: fc1efd09dd375502b3e97977168262874d71e66d MIME-Version: 1.0 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Original-Sender: toby@hornetnode.org X-Original-Authentication-Results: gmr-mx.google.com; dkim=pass header.i=@hornetnode.org header.s=protonmail2 header.b=sid8zHFO; spf=pass (google.com: domain of toby@hornetnode.org designates 109.224.244.117 as permitted sender) smtp.mailfrom=toby@hornetnode.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=hornetnode.org X-Original-From: Toby Sharp Reply-To: Toby Sharp Precedence: list Mailing-list: list bitcoindev@googlegroups.com; contact bitcoindev+owners@googlegroups.com List-ID: X-Google-Group-Id: 786775582512 List-Post: , List-Help: , List-Archive: , List-Unsubscribe: , X-Spam-Score: -1.0 (-) Hi Eric, Thanks for your thoughtful and encouraging comments, and for sharing some o= f the libbitcoin implementation. I find libbitcoin to be impressive in scope and pleasant in design, and hop= e that it continues to gain recognition and adoption. I also find it signif= icant that Hornet and libbitcoin independently converged on a principle of = isolated consensus rules, and soon it will be interesting to compare them s= ide-by-side and study any differences. For this reason, I think it's rather good that the Hornet spec and code has= been developed independently from libbitcoin, since two independent and co= nvergent derivations greatly strengthen the case that the resulting rule se= t is complete and correct -- not an artifact of a single codebase's design = assumptions. The architectural distinction I'd note is in composition. Libbitcoin isolat= es rules as predicates but composes them inside phase-specific methods as i= f-chains. This is excellent for a clean and readable node implementation. H= ornet goes further and composes them in a static declarative graph using an= algebra of combinators (All, With, Each). This makes the spec itself a fir= st-class data structure that is traversable, renderable, executable, and la= ter replaceable with a DSL representation. I see this as the step that take= s consensus isolation toward language-neutral consensus specification. On widespread use: Hornet Node today is more of an experimental client for = validation and IBD than a fully functional node. This is by design, as the = main target at this stage is the neutral specification, and demonstration o= f how it can be efficiently and verifiably implemented for IBD. Collaborati= on with existing clients would be ideal. Some suggestions on collaboration might include: cross-validating libbitcoi= n's predicate set against Hornet's 34 semantic invariants to identify and r= esolve any divergence; joint review of the DSL as it develops; discussion o= n how we might verify that libbitcoin exactly implements the specification;= and sharing a corpus of edge-case test vectors. Happy to take any of this to direct email. Best wishes, T# Sent with Proton Mail secure email. On Wednesday, April 15th, 2026 at 5:21 PM, eric@voskuil.org wrote: > Hi Toby, >=20 > I very much support your effort to produce a formal specification. Libbit= coin requires the isolation of consensus rules into purely functional boole= an methods with names that identify the rule under evaluation. I've pasted = the list of these header/tx/block functions below. You'll notice that `inte= rpreter::connect()` is evaluated with `transaction::connect()`. This declar= ative pattern continues into all of script evaluation, but is too large to = include. The declarative opcode evaluation portion can be seen here: https:= //github.com/libbitcoin/libbitcoin-system/blob/master/include/bitcoin/syste= m/impl/machine/interpreter.ipp . There are of course certain design decisio= ns that affect the specific organization, but the outcome is the same. Each= rule requires and name and functional, isolated evaluation. >=20 > We see this as the way forward, and are excited to see you tackling the f= ormality aspect. We are looking forward to collaborating with you on it. It= is essential to the usefulness of the formalization that it be applied to = a node in widespread use. So while we long ago implemented the required con= sensus isolation, we have spent years on the many other aspects of high-per= formance node design. This gives me hope that we can make meaningful progre= ss on the formalization as well. As you know there is real interest in the = community to make this happen. >=20 > Best, > Eric >=20 > // header > // ----------------------------------------------------------------------= ------ >=20 > code header::check() const > { > if (is_invalid_proof_of_work()) > return error::invalid_proof_of_work; > if (is_futuristic_timestamp()) > return error::futuristic_timestamp; >=20 > return error::block_success; > } >=20 > code header::accept(const context& ctx) const > { > if (ctx.is_insufficient_version(version_)) > return error::insufficient_block_version; > if (ctx.is_anachronistic_timestamp(timestamp_)) > return error::anachronistic_timestamp; > if (ctx.is_invalid_work(bits_)) > return error::incorrect_proof_of_work; >=20 > return error::block_success; > } >=20 > // transaction > // ----------------------------------------------------------------------= ------ >=20 > code transaction::check() const > { > const auto coinbase =3D is_coinbase(); >=20 > if (is_empty()) > return error::empty_transaction; > if (coinbase && is_invalid_coinbase_size()) > return error::invalid_coinbase_script_size; > if (!coinbase && is_null_non_coinbase()) > return error::previous_output_null; >=20 > return error::transaction_success; > } >=20 > code transaction::check(const context& ctx) const > { > const auto bip113 =3D ctx.is_enabled(bip113_rule); >=20 > if (is_absolute_locked(ctx.height, ctx.timestamp, > ctx.median_time_past, bip113)) > return error::absolute_time_locked; >=20 > return error::transaction_success; > } >=20 > code transaction::accept(const context&) const > { > if (is_coinbase()) > return error::transaction_success; > if (is_missing_prevouts()) > return error::missing_previous_output; > if (is_overspent()) > return error::spend_exceeds_value; >=20 > return error::transaction_success; > } >=20 > code transaction::confirm(const context& ctx) const > { > const auto bip68 =3D ctx.is_enabled(bip68_rule); >=20 > if (is_coinbase()) > return error::transaction_success; > if (bip68 && is_relative_locked(ctx.height, ctx.median_time_past)) > return error::relative_time_locked; > if (is_immature(ctx.height)) > return error::coinbase_maturity; > if (is_unconfirmed_spend(ctx.height)) > return error::unconfirmed_spend; > if (is_confirmed_double_spend(ctx.height)) > return error::confirmed_double_spend; >=20 > return error::transaction_success; > } >=20 > code transaction::connect(const context& ctx) const > { > if (is_coinbase()) > return error::transaction_success; >=20 > for (auto in =3D inputs_->begin(); in !=3D inputs_->end(); ++in) > if (const auto ec =3D interpreter::connect(ctx, *this, in)) > return ec; >=20 > return error::transaction_success; > } >=20 > // block > // ----------------------------------------------------------------------= ------ >=20 > code block::check() const > { > if (is_oversized()) > return error::block_size_limit; > if (is_first_non_coinbase()) > return error::first_not_coinbase; > if (is_extra_coinbases()) > return error::extra_coinbases; > if (is_forward_reference()) > return error::forward_reference; > if (is_internal_double_spend()) > return error::block_internal_double_spend; > if (is_invalid_merkle_root()) > return error::invalid_transaction_commitment; >=20 > return check_transactions(); > } >=20 > code block::check(const context& ctx) const > { > const auto bip141 =3D ctx.is_enabled(bip141_rule); > const auto bip34 =3D ctx.is_enabled(bip34_rule); > const auto bip50 =3D ctx.is_enabled(bip50_rule); >=20 > if (bip141 && is_overweight()) > return error::block_weight_limit; > if (bip34 && is_invalid_coinbase_script(ctx.height)) > return error::coinbase_height_mismatch; > if (bip50 && is_hash_limit_exceeded()) > return error::temporary_hash_limit; > if (bip141 && is_invalid_witness_commitment()) > return error::invalid_witness_commitment; >=20 > return check_transactions(ctx); > } >=20 > code block::accept(const context& ctx) const > { > const auto bip16 =3D ctx.is_enabled(bip16_rule); > const auto bip42 =3D ctx.is_enabled(bip42_rule); > const auto bip141 =3D ctx.is_enabled(bip141_rule); >=20 > if (is_overspent(ctx.height, bip42)) > return error::coinbase_value_limit; > if (is_signature_operations_limited(bip16, bip141)) > return error::block_sigop_limit; >=20 > return accept_transactions(ctx); > } >=20 > > -----Original Message----- > > From: 'Toby Sharp' via Bitcoin Development Mailing List > > > > Sent: Wednesday, April 15, 2026 6:43 PM > > To: Bitcoin Development Mailing List > > Subject: [bitcoindev] Hornet Update: A declarative executable specifica= tion of > > Bitcoin consensus rules > > > > In September 2025, I published a paper on my work towards a pure, forma= l > > specification of Bitcoin's consensus rules. > > > > > Hornet Node and the Hornet DSL: A minimal, executable specification o= f > > Bitcoin consensus. T Sharp, September 2025. > > https://hornetnode.org/paper.html > > > > I have now completed the C++ executable declarative specification for n= on- > > script block validation rules: 34 semantic invariants in total. > > > > ## Background > > > > Hornet is a minimal, executable specification of Bitcoin's consensus ru= les, > > expressed both in declarative C++ and in a purpose-built domain-specifi= c > > functional language. > > > > It is implemented as a suite of modular, dependency-free, modern C++ > > libraries and includes a lightweight node capable of Initial Block Down= load > > (IBD). > > > > Hornet's concurrent, lock-free UTXO(1) engine achieves an 11=C3=97 vali= dation > > speedup over Bitcoin Core on full-chain replay (discussed in Bitcoin Op= tech > > Newsletter #391). All consensus logic is encapsulated by the declarativ= e > > specification described below. > > > > ## Update 2026-04-15 > > > > The question of whether a block is valid or invalid can -- and should -= - be > > expressed as a Boolean, pure function without state changes or side eff= ects. > > > > Hornet aims to specify this logic declaratively and semantically, both = in C++ > > and in a functional domain-specific language. > > > > I have now completed the set of non-script block validation rules, orga= nized > > with one semantic invariant per rule, with a total of 34 rules composed= via a > > simple algebra. The first 15 rules are shown below. > > > > ```cpp > > // BLOCK VALIDITY SPECIFICATION > > static constexpr auto kConsensusRules =3D All{ > > With{MakeHeaderContext, All{ // ## Header Rules > > Rule{ValidatePreviousHash}, // A header MUST referenc= e the hash of > > a valid parent block. > > Rule{ValidateProofOfWork}, // A header's hash MUST a= chieve its > > own proof-of-work target. > > Rule{ValidateDifficultyAdjustment}, // A header's proof-of-wo= rk target > > MUST satisfy the difficulty adjustment formula for the timechain. > > Rule{ValidateMedianTimePast}, // A header timestamp MUS= T be > > strictly greater than the median of its 11 ancestors' timestamps. > > Rule{ValidateTimestampCurrent}, // A header timestamp MUS= T be less > > than or equal to network-adjusted time plus 2 hours. > > Rule{ValidateVersion} // A header's version num= ber MUST NOT > > have been retired by any activated soft fork. > > }}, > > With{MakeEnvironmentContext, All{ All{ // ## Local Rules > > Rule{ValidateNonEmpty}, // A block MUST contain a= t least one > > transaction. > > Rule{ValidateMerkleRoot}, // A block=E2=80=99s Merk= le root field MUST equal > > the unique Merkle root of its transactions. > > Rule{ValidateOriginalSizeLimit}, // A block=E2=80=99s seri= alized size excluding > > witness flags and data MUST NOT exceed 1,000,000 bytes. > > Rule{ValidateCoinbase}, // A block's first transa= ction MUST be its > > only coinbase transaction. > > Rule{ValidateSignatureOps}, // The total legacy signa= ture-operation > > count over all input and output scripts MUST NOT exceed 20,000. > > Each{TransactionsInBlock{}, All{ > > Rule{ValidateInputCount}, // A transaction MUST con= tain at least > > one input. > > Rule{ValidateOutputCount}, // A transaction MUST con= tain at least > > one output. > > Rule{ValidateTransactionSize}, // A transaction's serial= ized size > > excluding witness flags and data MUST NOT exceed 1,000,000 bytes. > > Rule{ValidateOutputsNonNegative}, // All transaction output= amounts > > MUST be non-negative. > > ... > > ``` > > > > The declarative specification separates *what must be true* from *how i= t is > > computed*. Each `Rule` line names a C++ function that validates the spe= cific > > semantic rule in question, and also gives an English description of the= rule > > being enforced. > > > > The above statically-typed declarative graph is the executable specific= ation of > > the semantic invariants that precisely determine consensus validity of = a block > > in the Bitcoin network. Each Rule node names a validation function that > > returns a unique error code if and only if that property fails to hold. > > > > We can parse the same code to automatically generate an English table o= f the > > semantic rules: > > > > | ID | Rule | > > |-|-| > > ||**Header Rules** > > H01|A header MUST reference the hash of a valid parent block. > > H02|A header's hash MUST achieve its own proof-of-work target. > > H03|A header's proof-of-work target MUST satisfy the difficulty adjustm= ent > > formula for the timechain. > > H04|A header timestamp MUST be strictly greater than the median of its = 11 > > ancestors' timestamps. > > H05|A header timestamp MUST be less than or equal to network-adjusted > > time plus 2 hours. > > H06|A header's version number MUST NOT have been retired by any > > activated soft fork. > > ||**Local Rules** > > L01|A block MUST contain at least one transaction. > > L02|A block=E2=80=99s Merkle root field MUST equal the unique Merkle ro= ot of its > > transactions. > > L03|A block=E2=80=99s serialized size excluding witness flags and data = MUST NOT > > exceed 1,000,000 bytes. > > L04|A block's first transaction MUST be its only coinbase transaction. > > L05|The total legacy signature-operation count over all input and outpu= t > > scripts MUST NOT exceed 20,000. > > L06|A transaction MUST contain at least one input. > > L07|A transaction MUST contain at least one output. > > L08|A transaction's serialized size excluding witness flags and data MU= ST NOT > > exceed 1,000,000 bytes. > > L09|All transaction output amounts MUST be non-negative. > > ... > > > > For the full declarative C++ spec, see > > https://github.com/tobysharp/hornet/tree/main/src/hornetlib/consensus/r= u > > les/spec.h > > > > For the resulting semantic summary table, see > > https://hornetnode.org/spec.html. > > > > To read more about Hornet and how it relates to other projects, see > > https://hornetnode.org/overview.html. > > > > ## Future work > > > > The spending rule S06: "A non-coinbase input MUST satisfy the spent out= put's > > locking script" is correct, but on its own clearly doesn't capture the = internal > > complexity of script execution. I am working towards a separate layer o= f > > specification for script rules. > > > > The declarative C++ specification is a step towards a pure, functional = domain- > > specific language for a Bitcoin consensus spec. This will be implemente= d in a > > future iteration, together with an interpreter and/or compiler. Here is= an > > example of the Hornet DSL: > > > > ``` > > // The total number of signature operations in a block MUST NOT exceed = the > > consensus maximum. > > Rule SigOpLimit(block =E2=88=88 Block) > > Let SigOpCost : (op =E2=88=88 OpCode) -> int32 > > |-> =E2=8E=A7 1 if op =E2=88=88 {Op_CheckSig, Op_CheckSigVer= ify }, > > =E2=8E=A8 20 if op =E2=88=88 {Op_CheckMultiSig, Op_CheckMultiS= igVerify}, > > =E2=8E=A9 0 otherwise > > Require =CE=A3 SigOpCost(inst.opcode) > > =E2=88=80 inst =E2=88=88 script.instructions > > =E2=88=80 script =E2=88=88 tx.inputs.scriptSig =E2=A7=BA tx= .outputs.scriptPubKey > > =E2=88=80 tx =E2=88=88 block.transactions > > =E2=89=A4 20,000 > > ``` > > > > ## Conclusion > > > > I welcome feedback from the developer community. In particular, do you > > believe there is value in a formal specification of consensus rules? Ar= e there > > any aspects of Hornet that you like or dislike? Are there any rules tha= t you > > believe are missing, redundant, unclear, or incorrect? I also welcome a= ny bug > > reports. Thank you. > > > > T# >=20 >=20 >=20 --=20 You received this message because you are subscribed to the Google Groups "= Bitcoin Development Mailing List" group. To unsubscribe from this group and stop receiving emails from it, send an e= mail to bitcoindev+unsubscribe@googlegroups.com. To view this discussion visit https://groups.google.com/d/msgid/bitcoindev/= zGGdGeFp__snuJMlaMKpM0br91-R0cWc1Igwz2eTdnu6TWSO3CySfSNgmU6hL-OyJQXBG1j6tOD= 66Dm_Llw35T9R5N_VgP8Y9wEdqKjC9_I%3D%40hornetnode.org.