Argonmine — Consensus Specification v0.1 (draft)
Status: DRAFT. Every rule here is consensus-critical unless marked policy. Nothing in this document is final until the mainnet genesis block is mined. Names: chain Argonmine, unit ARG, smallest unit "unit" (1 ARG = 100,000,000 units). Domain argonmine.com.
0. Honesty note on "no mistakes"
No non-trivial software can be proven free of bugs. What this project does instead:
- Minimal consensus surface. No scripting language in v1. One signature scheme. One output type that moves value. Fewer rules means fewer places to be wrong.
- Every rule written down here first, then implemented, then tested against the written rule.
- Every known Bitcoin consensus bug or design regret (section 9) has a specific rule here that prevents it, and a test that exercises it.
- Canonical, round-trip-exact serialization. Anything non-canonical is invalid.
- Checked integer arithmetic everywhere money or time is handled.
- Testnet first, then an external review, then mainnet. Mainnet parameters are frozen only after that.
1. Chain parameters
| Parameter | Value | Note |
|---|---|---|
| Smallest unit | 1 unit = 1e-8 ARG | same as satoshi |
| MAX_MONEY | 21,000,000 × 1e8 = 2,100,000,000,000,000 units | fits in int64 with large margin |
| Initial block subsidy | 50 ARG | |
| Halving interval | 210,000 blocks | |
| Subsidy after 64 halvings | 0 | explicit, not shift-UB |
| Target block interval | 600 s | |
| Difficulty algorithm | ASERT (absolute exponential) | section 5 |
| ASERT half-life | 86,400 s (1 day) | faster response than BCH's 2 days, because app-miner hashrate is volatile |
| Proof of work | Argon2id over the 120-byte header | section 4 |
| Argon2id params | time=1, memory=8 MiB (8192 KiB), lanes=1, keyLen=32, salt=POW_SALT |
consensus constants |
| Coinbase maturity | 100 blocks | |
| Max block serialized size | 1,000,000 bytes (incl. witnesses) | one simple limit, no weight |
| Max tx serialized size | 100,000 bytes (consensus) | |
| Max inputs per tx / outputs per tx | 10,000 / 10,000 | bounded, anti-DoS |
| Max future block time | 7,200 s ahead of the node's local clock (no network time adjustment; operators run NTP) | |
| Median time past window | 11 blocks | |
| Timestamp width | 64-bit unsigned seconds | no year-2106 problem |
| Nonce width | 64-bit | no extra-nonce in coinbase needed |
| Genesis coinbase | NOT added to UTXO set | explicit, unlike Bitcoin's accident |
| Premine | none | |
| Address format | bech32m, HRP arg (mainnet) targ (testnet) rarg (regtest) |
2. Primitives
2.1 Hashes
H(tag, data)= SHA-256( SHA-256(tag) || SHA-256(tag) || data ). This is the BIP-340 tagged hash. Every hash in the protocol has its own tag so that no two hash domains can collide.- Tags:
Argonmine/block,Argonmine/txid,Argonmine/wtxid,Argonmine/merkle/leaf,Argonmine/merkle/node,Argonmine/sighash,Argonmine/prevouts,Argonmine/amounts,Argonmine/scripts,Argonmine/outputs. - Block hash (block identifier) =
H("Argonmine/block", header_bytes). This is NOT the proof-of-work hash. - PoW hash =
Argon2id(password=header_bytes, salt=POW_SALT, t=1, m=8192 KiB, p=1, keyLen=32), interpreted as a 256-bit little-endian integer and compared to the target.
2.2 Integers and encoding
- Fixed-width integers are little-endian.
varint: unsigned LEB128 (base-128, little-endian groups, continuation bit), maximum 9 bytes (≤ 2^63 − 1). Encoding MUST be minimal: a trailing group of0x00or any encoding longer than necessary is invalid. (Replaces Bitcoin's CompactSize, which has non-canonical forms.)- Amounts are
int64in units. Valid range for every single output and for every sum is0 ≤ x ≤ MAX_MONEY. Every addition is checked for overflow before being compared. Any out-of-range value anywhere makes the transaction invalid. - Byte strings:
varint length || bytes.
2.3 Merkle tree
- Leaf hash:
H("Argonmine/merkle/leaf", txid)(or wtxid for the witness tree). - Node hash:
H("Argonmine/merkle/node", left || right). - If a level has an odd number of nodes, the last node is promoted unchanged to the next level (RFC 6962 style). Nothing is ever duplicated. Hence no two distinct transaction lists have the same root (CVE-2012-2459 impossible), and leaves can never be confused with internal nodes (64-byte confusion impossible).
- Empty tree is invalid (every block has ≥ 1 transaction).
2.4 Keys and signatures
- Curve secp256k1. Public keys are 32-byte x-only (BIP-340). Signatures are 64-byte BIP-340 Schnorr. Verification is exactly BIP-340; no other encodings exist.
- Batch verification is allowed in implementations but must give identical accept/reject results.
3. Data structures
3.1 Block header (120 bytes, fixed)
version u32 consensus version, MUST be 1
prev_hash 32B block hash of parent
tx_root 32B merkle root over txids
witness_root 32B merkle root over wtxids
time u64 unix seconds
bits u32 compact target (section 5.1)
nonce u64
3.2 Transaction
version u32 MUST be 1 (ARG only) or 2 (assets, section 3.5)
lock_height u32 tx valid only in a block with height >= lock_height
inputs varint n, then n × { prev_txid 32B, prev_index u32 }
outputs varint m, then m × { amount i64, type u8, payload bytes(varint-len) [, asset 32B if version 2] }
issuances version 2 only: varint k (0 or 1), then k × { asset 32B, issuer 32B, symbol bytes(varint-len), amount i64 }
witnesses (n + k) × bytes(varint-len) one per input, then one per issuance, in order
txid=H("Argonmine/txid", serialization WITHOUT witnesses).wtxid=H("Argonmine/wtxid", full serialization).n ≥ 1,m ≥ 1. (A tx with no inputs or no outputs is invalid.)- Output types:
0x00 P2PK: payload = 32-byte x-only pubkey. Spent by a 64-byte Schnorr signature in the witness (section 6.2).0x01 NULLDATA: payload ≤ 80 bytes,amountMUST be 0. Unspendable, never enters the UTXO set.- any other type: invalid. Upgrades are coordinated version bumps (hard forks), not anyone-can-spend soft forks. This is a deliberate trade: no silent anyone-can-spend footgun.
- Payload length for type 0 MUST be exactly 32; for type 1 MUST be ≤ 80. Anything else invalid.
- Decoders reject any output payload longer than 80 bytes and any witness longer than 100 bytes while parsing (no valid output or witness can be longer), so such a transaction fails §6.1 step 1 rather than a later step. The verdict is the same on every node.
3.3 Coinbase transaction
- Exactly one input with
prev_txid = 0x00…00andprev_index = 0xFFFFFFFF. lock_heightMUST equal the block height. This makes every coinbase txid unique across the chain (BIP-34 purpose) without any script.- Its single witness is the "miner tag": arbitrary bytes, length ≤ 100. (It is in wtxid, not txid.)
- Sum of outputs ≤ subsidy(height) + total fees of the block (checked arithmetic).
- Coinbase outputs are spendable only at height ≥ creation height + 100.
- Only the first transaction of a block may be a coinbase; any other tx with a null prevout is invalid.
3.4 Block
header 120 B
txs varint count, then each transaction (full serialization)
- Total serialized size ≤ 1,000,000 bytes.
tx_rootMUST equal merkle(txids),witness_rootMUST equal merkle(wtxids).- No duplicate txid within a block. No two inputs anywhere in the block spend the same outpoint (CVE-2018-17144 class).
3.5 Assets (version-2 transactions)
A version-2 transaction can hold and move units of assets other than ARG, and can create units of an asset with an issuance. ARG is never issued: it comes from the coinbase only. Every existing block is a version-1 object and is unchanged by this section.
- Every output of a version-2 transaction carries a 32-byte
asset. The zero hash is ARG. A version-1 output is ARG by definition (no field). asset = H("Argonmine/asset", issuer_xonly_pubkey 32B || varbytes(symbol))wheresymbolis 1-8 characters ofA-Zand0-9. The id therefore binds the issuer key and the ticker; two issuers can use the same ticker and get two different assets.- An issuance creates
amountunits ofassetin this transaction. The transaction's last witness MUST be a 64-byte BIP-340 signature byissueroversighash(tx, 0xFFFFFFFF). At most one issuance per transaction. - Amount bounds for non-ARG outputs and issuances:
1 ≤ amount ≤ 2^62(MAX_ASSET_AMOUNT); per-asset sums are checked against the same bound. NULLDATA outputs are ARG only (amount 0). - Conservation is per asset: for each non-ARG asset,
Σ outputs ≤ Σ spent inputs + issued. The difference, if any, is burned. ARG keeps rule 6.2.3; asset units never count toward ARG and never pay fees. Fees are ARG only, so miners are paid in the coin they mine and tokens cannot spam the chain for free. - A version-1 transaction MUST NOT spend an output whose asset is not ARG (it could not express the asset and would destroy it silently).
- The coinbase MUST NOT carry an issuance or a non-ARG output.
- Version-2 sighash: two further hashes are committed after
outputs:H("Argonmine/assets", all spent asset ids in order)andH("Argonmine/issuance", varint k || issuances serialized), so a signer cannot be misled about which asset it spends or creates. - Asset units never enter the ARG supply figures; wallets and explorers account for them per asset id.
4. Proof of work
- A header is valid PoW iff
PoWHash(header) ≤ target(bits)andtarget(bits) ≤ POW_LIMIT. POW_LIMIT(easiest allowed target) = compact0x1E400000= 2^238, i.e. an expected 2^18 = 262,144 Argon2id evaluations per block. This floor is deliberately not trivial: a header on a side chain costs an attacker real work, and a lone fast machine cannot mint the first blocks after launch in seconds, while a small honest network of ~1 kH/s still finds blocks in minutes. Testnet (0x1F7FFFFF, 512 hashes) and regtest (0x207FFFFF, ~2 hashes) have easier limits.POW_SALT= the ASCII bytesArgonmine/pow/v1(Argon2id requires a salt; it is a constant because the header carries all per-block entropy).- Argon2id is memory-hard (8 MiB working set per hash attempt), so phones and laptops are competitive and ASICs gain little. Verification costs one Argon2id evaluation (~5–15 ms); headers-first sync verifies PoW before anything else and bans peers who send headers that fail PoW.
5. Difficulty: ASERT
5.1 Compact target
Same encoding as Bitcoin nBits (1-byte exponent, 3-byte mantissa) but strictly canonical:
- mantissa high bit (sign bit in Bitcoin) MUST be 0 → reject if set.
- mantissa MUST be minimal:
Compact(TargetFromCompact(bits)) == bitsmust hold, else invalid. - target
0is invalid. Target > POW_LIMIT is invalid.
5.2 Next-block target
Let the anchor be the genesis block: A_height = 0, A_target = TargetFromCompact(genesis.bits), and define the anchor's virtual parent time A_ptime = genesis.time − 600 (the reference algorithm anchors on the parent time of the anchor block; genesis has no parent, so it is defined to have been exactly on schedule).
For a block at height h with parent P (height h−1):
time_delta = P.time − A_ptime (parent timestamp minus anchor parent time; computed without overflow)
height_delta = (h − 1) − A_height = h − 1
num = time_delta − 600 × (height_delta + 1) saturated to ±(2^47 − 1)
exponent = (num × 65536) / 86400 // 16 fractional bits, division truncates toward zero (as in C++)
At height 1 with P = genesis, num = 0 and the target equals A_target exactly.
Implementations may additionally saturate time_delta itself to ±(2^47 − 1) before the subtraction (the reference implementation does); every input where the two orders differ already clamps the result to POW_LIMIT or 1, so the outcome is identical.
Then target = A_target × 2^(exponent / 2^16), computed exactly as in the aserti3-2d reference:
shifts = exponent >> 16 (arithmetic shift, i.e. floor)
frac = exponent & 0xFFFF
factor = 65536 + ((195766423245049 × frac + 971821376 × frac² + 5127 × frac³ + 2^47) >> 48)
target = A_target × factor
shifts -= 16
if shifts < 0: target >>= −shifts else: target <<= shifts
if target == 0: target = 1
if target > POW_LIMIT: target = POW_LIMIT
bits = Compact(target)
- Because the schedule is absolute (anchored at genesis) there is no cumulative drift and no per-period off-by-one (Bitcoin's 2015-vs-2016 timewarp root cause does not exist).
- Regtest: difficulty is constant (
bits = POW_LIMIT_REGTEST) to make tests deterministic.
5.3 Timestamp rules
time > MedianTimePast(previous 11 blocks)(strictly greater).time ≤ local adjusted time + 7,200 s(nodes reject but do not ban; the block may become valid later).- Together with ASERT, the attacker's ability to move difficulty by lying about time is bounded to the 2-hour window and decays with half-life.
6. Transaction validation
6.1 Stateless (no UTXO needed)
- Canonical deserialization succeeds and re-serialization is byte-identical.
version ∈ {1, 2}; issuances and non-ARG outputs only in version 2.1 ≤ inputs ≤ 10,000,1 ≤ outputs ≤ 10,000, size ≤ 100,000 bytes.- No two inputs reference the same outpoint.
- Every ARG output:
0 ≤ amount ≤ MAX_MONEY; type/payload rules of 3.2;Σ ARG amounts ≤ MAX_MONEY(checked add). Every non-ARG output and issuance: rules of 3.5, per-asset sums ≤ MAX_ASSET_AMOUNT (checked add). At most one issuance, and it must matchH(issuer || symbol). - Exactly one witness per input, plus one per issuance.
- If not coinbase: no input has the null prevout. If coinbase: rules of 3.3.
6.2 Stateful (needs UTXO set, block height h)
lock_height ≤ h.- Every input's outpoint exists in the UTXO set (unspent), is not a NULLDATA output (they are never in the set), and if it is a coinbase output then
h ≥ its_height + 100. Σ ARG input amounts ≤ MAX_MONEY(checked),fee = Σ ARG in − Σ ARG out ≥ 0.- For each input
ispending a P2PK output with pubkeypk: witnessiMUST be exactly 64 bytes and a valid BIP-340 signature bypkoversighash(tx, i). - Version 2 only: for every non-ARG asset,
Σ out ≤ Σ in + issued(3.5); a version-1 transaction spending a non-ARG output is invalid. - Version 2 with an issuance: witness
nMUST be a valid signature by the issuer oversighash(tx, 0xFFFFFFFF).
Sighash (all-inputs, all-outputs; there is only one sighash type):
sighash(tx, i) = H("Argonmine/sighash",
CHAIN_TAG 32B = genesis block hash (replay protection across networks/forks)
|| version u32 || lock_height u32
|| H("Argonmine/prevouts", all (prev_txid||prev_index) in order)
|| H("Argonmine/amounts", all spent amounts i64 in order)
|| H("Argonmine/scripts", all spent (type u8 || payload as a byte string: varint(len) || bytes) in order)
|| H("Argonmine/outputs", all outputs serialized in order)
|| [version 2 only: H("Argonmine/assets", spent asset ids) || H("Argonmine/issuance", issuances)]
|| i u32 )
Committing to all spent amounts and spent scripts means an offline signer cannot be tricked about fees (BIP-143 problem) and cannot be made to sign for a different output type.
7. Block validation (connect to chain tip)
- Header:
version == 1,prev_hashis the tip, PoW valid,bits == ExpectedBits(parent), timestamp rules (5.3). - Size limit. First tx is coinbase, no other tx is coinbase.
- Merkle roots match. No duplicate txids. No duplicate outpoints spent anywhere in the block.
- Every tx passes 6.1; every non-coinbase tx passes 6.2 against a UTXO view that is updated sequentially (a tx may spend an output created earlier in the same block, never later).
- Coinbase outputs sum ≤
Subsidy(h) + Σ fees(checked). - Apply: remove spent outputs, add new P2PK outputs (never NULLDATA; never genesis outputs). Write undo data so the block can be disconnected on reorg.
Fork choice: the valid chain with the greatest total work (Σ 2^256 / (target+1)) wins. Ties: first seen.
8. Subsidy
Subsidy(h): halvings = h / 210000
if halvings >= 64: return 0
return 50 × 1e8 >> halvings
Total emission is strictly below MAX_MONEY (equal to Bitcoin's 20,999,999.9769 ARG).
9. Bitcoin pitfalls and the rule here that prevents each
| Bitcoin issue | Year | Rule here |
|---|---|---|
| Value overflow, 184 billion BTC created (CVE-2010-5139) | 2010 | §2.2 checked arithmetic + per-output and per-sum MAX_MONEY, §6.1.5, §6.2.3 |
| OP_RETURN "always true" script bug, OP_CHECKMULTISIG off-by-one, SIGHASH_SINGLE bug, FindAndDelete quirks | 2010+ | No script language. §3.2 |
| Merkle duplicate-leaf collision (CVE-2012-2459) | 2012 | §2.3 promote-odd, tagged leaf/node hashes |
| Token layers bolted on later (coloured coins, Omni) that nodes do not validate, so a wallet bug can create or destroy tokens | 2013+ | §3.5: assets are consensus objects; per-asset conservation and issuer signatures are enforced by every node, ARG and tokens never mix, version-1 software cannot touch asset coins |
| 64-byte tx leaf/node confusion | 2017 (disclosed) | §2.3 domain separation |
| Transaction malleability (signature not in txid) | 2014 | §3.2 txid excludes witnesses; witness committed in header via witness_root |
| Non-strict DER / OpenSSL parsing fork risk (BIP-66) | 2015 | §2.4 fixed 64-byte Schnorr only |
| Duplicate coinbase txids (BIP-30/34) | 2012 | §3.3 coinbase lock_height == height |
| Duplicate-input inflation (CVE-2018-17144) | 2018 | §6.1.4 within tx, §3.4 across block, always checked |
| Timewarp: retarget over 2015 blocks and unconstrained period boundary | known since 2011 | §5 ASERT, absolute schedule, no periods |
Time-based vs height-based locktime confusion, nLockTime 500M split |
design | §3.2 lock_height only |
| 32-bit timestamp (year 2106) | design | §3.1 u64 time |
| 32-bit nonce forcing extra-nonce in coinbase | design | §3.1 u64 nonce |
| Genesis coinbase accidentally unspendable | 2009 | §1 made explicit |
| BDB lock exhaustion chain split (0.7 vs 0.8) | 2013 | §3.4 single explicit byte limit; storage layer never influences validity |
| Shift of subsidy by ≥ 64 is C undefined behaviour | design | §8 explicit 0 |
| Non-canonical CompactSize encodings | design | §2.2 minimal LEB128 only |
| Signer cannot see amounts (hardware wallet fee attack, fixed by BIP-143) | 2016 | §6.2 sighash commits to all spent amounts and scripts |
| Replay of signatures across forks / testnets | design | §6.2 CHAIN_TAG |
| Bech32 length-extension weakness | 2019 | §1 bech32m |
| Sign bit in compact target allows negative targets | design | §5.1 canonical compact, sign bit rejected |
| Unbounded orphan/mempool growth, inv flooding | ops | policy, node layer |
10. Policy (non-consensus, node defaults)
- Min relay fee 1 unit/byte; dust limit 546 units for ARG P2PK outputs; max standard tx 100,000 bytes; full RBF by fee; mempool cap 300 MB.
- Asset outputs have no dust limit (asset units have no ARG value). Instead every asset output beyond the first two in a transaction adds 546 units (
-assetoutputfee) to the minimum relay fee, so an asset UTXO costs about what an ARG one does. A payment with its change, or one issuance output, pays only for its bytes.mempool.MinRelayFeecomputes the minimum. - Chains of unconfirmed transactions: a transaction with all its unconfirmed ancestors, and every ancestor with all its unconfirmed descendants, at most 25 transactions and 101,000 bytes (Bitcoin's defaults). Making room in a full pool never evicts the newcomer's own ancestors. Block templates order transactions parents first, best fee rate first among those whose parents are placed.
- Rejections are remembered for 2 minutes and forgotten on every new tip. A failure that does not depend on the witness (dust, inputs, lock height, maturity, conflicts) is remembered by txid; one that does (signature, fee, size) only by wtxid, so a copy with a garbage witness cannot block the genuine transaction.
- Relay and connection limits are node policy too: NODE.md, "Connection limits".
11. Networks
| mainnet | testnet | regtest | |
|---|---|---|---|
| HRP | arg |
targ |
rarg |
| P2P port | 9333 | 19333 | 29333 |
| RPC port | 9332 | 19332 | 29332 |
| magic | 41 52 47 4D ("ARGM") |
54 41 52 47 ("TARG") |
52 41 52 47 ("RARG") |
| POW_LIMIT | compact 0x1E400000 (2^18 hashes) | compact 0x1F7FFFFF (512 hashes) | compact 0x207FFFFF, constant |
12. Where this chain is better than Bitcoin (by design, v1)
| Area | Bitcoin | This chain |
|---|---|---|
| Who can mine | ASIC farms only; a phone earns nothing | Memory-hard Argon2id: phones and laptops are competitive, so the mining app is real mining |
| Difficulty response | Every 2016 blocks (~2 weeks); hashrate swings cause long stalls or block floods | ASERT, every block, 1-day half-life; absolute schedule with no drift |
| Timewarp attack | Possible (unfixed, mitigated by soft-fork proposals) | Impossible by construction |
| Tx malleability | Fixed late via segwit workaround | Native: witness never in txid, committed in header |
| Signatures | ECDSA with DER encoding quirks; Schnorr only via taproot | BIP-340 Schnorr only, fixed 64 bytes |
| Fee-visibility for hardware wallets | Required BIP-143/341 patches | Sighash commits to every spent amount and script from day one |
| Replay across forks | None | Chain tag in every signature |
| Merkle tree | Duplicate-leaf and 64-byte confusion flaws | Tagged, promote-odd tree; no known weakness |
| Timestamp / nonce | 32-bit, breaks in 2106; extra-nonce hack in coinbase | 64-bit both |
| Encoding | Non-canonical CompactSize accepted in places | Single canonical encoding; anything else is invalid |
| Script engine | ~5 historical consensus bugs, large attack surface | None in v1; value transfer is the only operation |
| Supply bugs | 2010 overflow created 184 billion BTC; 2018 inflation bug | Checked arithmetic and MAX_MONEY on every amount and every sum |
| Upgrade path | Anyone-can-spend soft forks (subtle security trade-offs) | Explicit versioned hard forks; unknown types are invalid |
| Address checksum | bech32 (length-extension weakness) | bech32m |
Candidate upgrades that need a product decision (not in v1): shorter block time for app feedback, larger block size, privacy (confidential amounts / ring signatures), a safe smart-contract layer (predicates, not a VM), light-client proofs, encrypted P2P.
13. Open items before mainnet freeze
- Final chain name, unit name, HRP.
- Argon2id memory: 8 MiB chosen for phone friendliness vs verification cost; benchmark on target devices and freeze.
- ASERT half-life: 1 day chosen; simulate against hashrate swings of 10× before freezing.
- Genesis block contents and timestamp.