Reunite the two lines of this repository: the runnable package joins the anchor
The published line delivered the anchor (source and patch 0003) but had lost the chain configuration: no genesis, no run recipe. The unpublished local line had genesis.json, RUN-A-NODE.md and the measured claims, but predated the anchor. This commit carries the package files onto the anchor line: - genesis.json restored, byte for byte as the running nodes hold it - RUN-A-NODE.md restored; the basefee-floor patch returns as 0004; the anchor section states plainly that a build without patch 0003 has not been shown to import headers past block 13,014,000, and that an import proof for a patches-only build is the next thing this repository owes its reader - bootnodes are deliberately NOT published: today's entry points are consensus or origin hosts, and this project does not print its machines' addresses; a dedicated bootnode host is the planned replacement, an enode is available by mail until then
This commit is contained in:
parent
3f62a21a70
commit
a70d06fef6
21
CITATIONS-UNRESOLVED.md
Normal file
21
CITATIONS-UNRESOLVED.md
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Citations in this repository that you cannot open
|
||||||
|
|
||||||
|
This file is generated by the legaturi-repara.cjs script in the Aere working tree and
|
||||||
|
enforced by legaturi.cjs. It is the complete list, measured on 2026-08-11, of every
|
||||||
|
path cited in this repository that does not resolve to a published file.
|
||||||
|
|
||||||
|
A citation is a promise that a claim is checkable. Where the target is not published,
|
||||||
|
the claim is traceable but **not independently verifiable by you**, and it should be
|
||||||
|
read as our assertion. Nothing was deleted to produce this list: every path below is
|
||||||
|
still cited in the text exactly as our authors wrote it.
|
||||||
|
|
||||||
|
Paths that DO resolve are written relative to a side-by-side checkout of the Aere
|
||||||
|
repositories, so they begin with a repository name, for example
|
||||||
|
`aere-contracts/contracts/pqc/AereCryptoRegistry.sol`.
|
||||||
|
|
||||||
|
Unresolvable distinct paths in this repository: **4**.
|
||||||
|
|
||||||
|
- `aerenew/docs/DOVADA-PQC-VERIFICABILA-2026-07-20.md` cited in: aere-node/README.md
|
||||||
|
- `CHANGELOG.md` cited in: aere-node/README.md
|
||||||
|
- `LondonFeeMarket.java` cited in: aere-node/RUN-A-NODE.md
|
||||||
|
- `static-nodes.json` cited in: aere-node/README.md
|
||||||
84
LICENSING.md
Normal file
84
LICENSING.md
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
# Licensing
|
||||||
|
|
||||||
|
Default for this repository: **Apache License 2.0**, `Copyright 2026 AERE Network`. See `LICENSE`
|
||||||
|
and `NOTICE`.
|
||||||
|
|
||||||
|
This repository is the one Aere Network repository that is not MIT, and the reason is not style.
|
||||||
|
It contains code derived from Hyperledger Besu, and Besu is Apache-2.0. A permissive licence on
|
||||||
|
top of Apache-2.0 material is not a free choice: Apache-2.0 section 4 sets conditions on anyone who
|
||||||
|
redistributes, and those conditions are what this page records.
|
||||||
|
|
||||||
|
Where a file has its own `SPDX-License-Identifier`, **that header governs.** Every source file in
|
||||||
|
this repository carries one, and every one of them says `Apache-2.0`.
|
||||||
|
|
||||||
|
## Who wrote what, as measured
|
||||||
|
|
||||||
|
Read from the copyright line of every file under `precompiles/`.
|
||||||
|
|
||||||
|
| File | Copyright header | Origin |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `precompiles/Address.java` | `Copyright contributors to Hyperledger Besu.` | upstream, **modified by Aere Network** |
|
||||||
|
| `precompiles/MainnetPrecompiledContracts.java` | `Copyright contributors to Hyperledger Besu.` | upstream, **modified by Aere Network** |
|
||||||
|
| `precompiles/AereFalconSupport.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/Falcon512PrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/Falcon1024PrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/MLDSA44PrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/SLHDSA128sPrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/SHAKE256PrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/MLKEM768PrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
| `precompiles/HashToPointPrecompiledContract.java` | `Copyright contributors to the AERE Network.` | new, Aere Network |
|
||||||
|
|
||||||
|
Two upstream files, eight new ones. The diffs under `patches/` apply against upstream Besu commit
|
||||||
|
`d2032017bb3b8cb215a97303980a1e4a643f7180` and touch exactly those same two upstream files.
|
||||||
|
|
||||||
|
The eight new files are Aere Network's copyright and are still Apache-2.0 rather than MIT. They are
|
||||||
|
written to compile inside a Besu tree and they live in Besu's own package namespace,
|
||||||
|
`org.hyperledger.besu.evm.precompile` and `org.hyperledger.besu.datatypes`. Licensing them to match
|
||||||
|
the tree they are built for is what makes them usable where they are meant to be used.
|
||||||
|
|
||||||
|
## How this repository meets Apache-2.0 section 4
|
||||||
|
|
||||||
|
| Condition | Where it is met |
|
||||||
|
| --- | --- |
|
||||||
|
| **4(a)** give recipients a copy of the License | `LICENSE`, the full Apache-2.0 text |
|
||||||
|
| **4(b)** modified files carry prominent notices stating you changed them | a `Modifications Copyright 2026 Aere Network` block at the top of `precompiles/Address.java` and `precompiles/MainnetPrecompiledContracts.java`, naming what was changed and against which upstream commit. The same block is inside the diff bodies under `patches/`, so a tree with the patches applied carries it too. The two files are also named in `NOTICE` and in the patch commit messages |
|
||||||
|
| **4(c)** retain all copyright, patent, trademark and attribution notices from the source | `Address.java` and `MainnetPrecompiledContracts.java` keep their upstream `Copyright contributors to Hyperledger Besu.` headers unchanged |
|
||||||
|
| **4(d)** carry a readable copy of the upstream `NOTICE` attributions | `NOTICE`, which reproduces Besu's `NOTICE` in full, including the Tuweni and Apache Software Foundation attributions it in turn carries |
|
||||||
|
|
||||||
|
### Where the 4(b) notice lives, and a wrong turn we took first
|
||||||
|
|
||||||
|
The notice is a `Modifications Copyright` comment block at the top of each of the two modified files,
|
||||||
|
placed below the upstream copyright header and above the `package` declaration. The upstream header
|
||||||
|
itself is untouched, because 4(c) requires that; 4(b) is satisfied by the separate block underneath.
|
||||||
|
This is the shape OpenSearch uses on the Elasticsearch files it inherited, and it is the shape a
|
||||||
|
reader looking at a single copied file will actually see.
|
||||||
|
|
||||||
|
An earlier version of this page argued that the notice had to live in the patch commit message
|
||||||
|
instead, because putting it in the file would break the claim that `precompiles/` is byte-identical
|
||||||
|
to what the patches install. That argument was wrong, and it was wrong in an avoidable way: it
|
||||||
|
treated the patch as fixed. Put the notice **inside the diff body** and both properties hold at once.
|
||||||
|
The patch installs a file that already carries the notice, and `precompiles/` still matches it byte
|
||||||
|
for byte. There was never a trade to make.
|
||||||
|
|
||||||
|
The patch commit messages still describe the change, which is useful under `git am`, but nothing now
|
||||||
|
depends on the reader using `git am` rather than `git apply`.
|
||||||
|
|
||||||
|
## What is measured here
|
||||||
|
|
||||||
|
The byte-identity claim used to be recorded on this page as NOT MEASURED. It has now been measured,
|
||||||
|
on 2026-08-02, and the result is in `README.md` under "The patch": the base was confirmed against the
|
||||||
|
`index` pre-image hashes in patch `0001`, both patches applied at exit 0, all ten files that the
|
||||||
|
patches create or modify were compared against `precompiles/`, and the comparison found one real
|
||||||
|
mismatch. `Address.java` and `MainnetPrecompiledContracts.java` after **both** patches are not what
|
||||||
|
this repository ships; this repository ships them at the `0001` state, because `0x0ae6` and `0x0ae7`
|
||||||
|
are testnet-only. That is deliberate, and `README.md` now says so instead of claiming otherwise.
|
||||||
|
|
||||||
|
Still **NOT MEASURED**: whether the sources in `precompiles/` are the sources that built the binary
|
||||||
|
currently running on the validators. Nothing on this page or in `README.md` asserts a hash for that.
|
||||||
|
|
||||||
|
## Aere Network's other repositories
|
||||||
|
|
||||||
|
The rest of Aere Network's public code is MIT. This repository is Apache-2.0 because of what is in
|
||||||
|
it, not because of a different policy. If you are copying an Aere Network component and want to know
|
||||||
|
which licence applies, read the `LICENSE` file of the repository you are copying from, and the
|
||||||
|
`SPDX-License-Identifier` header of the file you are copying, which wins over both.
|
||||||
235
RUN-A-NODE.md
Normal file
235
RUN-A-NODE.md
Normal file
@ -0,0 +1,235 @@
|
|||||||
|
# Run a node on Aere Network mainnet, chain 2800
|
||||||
|
|
||||||
|
This file plus `genesis.json` plus one bootnode enode (see the bootnodes section below) is
|
||||||
|
everything an outsider needs to bring up a full node that syncs chain 2800 from block 0. Until
|
||||||
|
2026-08-03 this repository shipped the precompile sources and the NIST vectors but not the chain
|
||||||
|
configuration, so nobody outside the Foundation could actually start a node, and the "verify it
|
||||||
|
yourself" claim the repository is built on could not be exercised end to end.
|
||||||
|
|
||||||
|
Nothing here is a key. `genesis.json` is public chain configuration; a node that nobody can dial
|
||||||
|
is a node nobody can sync from, and the bootnodes section says plainly how dialing works today.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The three things you need
|
||||||
|
|
||||||
|
| What | Where |
|
||||||
|
|---|---|
|
||||||
|
| `genesis.json` | The genesis file, byte for byte as it sits on the Foundation nodes. sha256 `6f56eacada94457c1aa325c878399989e344dcf1d763e2d3b479f9b068784ed1` |
|
||||||
|
| a bootnode enode | requested by mail for now; see the bootnodes section below |
|
||||||
|
| `patches/`, `precompiles/` | The Besu fork, see `README.md`. Needed to sync past block 9,189,161 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Which Besu
|
||||||
|
|
||||||
|
Stock upstream Besu syncs chain 2800 correctly up to block **9,189,161** and then stops being able
|
||||||
|
to follow it. That block is the first with a timestamp at or after `activationTime` 1783820272, when
|
||||||
|
the five Aere post-quantum precompiles come into existence. A node without them computes a different
|
||||||
|
result for any block containing a call to `0x0AE1` through `0x0AE5` and falls off the chain.
|
||||||
|
|
||||||
|
So there are two honest paths:
|
||||||
|
|
||||||
|
- **Follow the tip.** Build the fork: apply `patches/0001-aere-pqc-precompiles-mainnet.patch` to
|
||||||
|
upstream Besu commit `d2032017bb3b8cb215a97303980a1e4a643f7180` and build it. Full instructions,
|
||||||
|
including the pre-image hashes that prove you are on the right base, are in `README.md`.
|
||||||
|
- **Verify the early chain only.** Stock Besu 26.4 or later will import blocks 0 through 9,189,160
|
||||||
|
from this genesis. That is enough to check the genesis allocation and the sub-second block period
|
||||||
|
transition against what we publish. It is not enough to reach the head.
|
||||||
|
|
||||||
|
There is a second Aere change to the client, and it is not in patch `0001`:
|
||||||
|
`patches/0004-aere-basefee-floor.patch`, one file, `LondonFeeMarket.java`. From block **10,141,734**
|
||||||
|
chain 2800 clamps the EIP-1559 base fee to a floor of 1 Gwei. The patch is fork gated by two JVM
|
||||||
|
system properties and is a byte behaviour no-op when they are unset, so a node that applies it
|
||||||
|
without setting them is stock Besu:
|
||||||
|
|
||||||
|
```
|
||||||
|
-Daere.basefee.floor.forkBlock=10141734 -Daere.basefee.floor.value=1000000000
|
||||||
|
```
|
||||||
|
|
||||||
|
Pass those through `BESU_OPTS`. Apply this patch and set these flags if you want a client that
|
||||||
|
computes what the network computes. It was measured on 2026-08-02 that QBFT and IBFT2 in Besu do not
|
||||||
|
validate the base fee at import at all, upstream or in our fork, so a node without this change is
|
||||||
|
expected to import the chain anyway and only to disagree if it ever proposed a block. That is a
|
||||||
|
finding about a missing upstream rule and not a licence to skip the patch.
|
||||||
|
|
||||||
|
Do not apply `patches/0002-...-testnet.patch` for a mainnet node. It adds `0x0AE6` and `0x0AE7`,
|
||||||
|
which are not on mainnet, and a node that has them will not disagree with the chain today but is
|
||||||
|
running a configuration the chain does not.
|
||||||
|
|
||||||
|
## The post-quantum header anchor: apply patch 0003 to follow the current chain
|
||||||
|
|
||||||
|
Since block 13,014,000 every 32nd header of chain 2800 carries a sixth element in its QBFT
|
||||||
|
`extraData`: a certificate of validator Falcon-512 seals, universal since block 13,889,296 and
|
||||||
|
enforced at a minimum of three seals per anchor block since 2026-08-14. From block 14,050,000 the
|
||||||
|
network refuses to finalize blocks without that post-quantum quorum.
|
||||||
|
|
||||||
|
The anchor ships in this repository both as source, under `anchor/`, and as
|
||||||
|
`patches/0003-aere-pq-anchor.patch`. A node built without it has not been shown to import
|
||||||
|
headers past block 13,014,000: the second client needed an explicit change to accept the sixth
|
||||||
|
element, and no floor-only build has been observed following the chain past that height. What
|
||||||
|
this repository does NOT yet contain is an import proof for a node built from these patches
|
||||||
|
alone, of the kind the rest of this file insists on; until that proof is added here, apply
|
||||||
|
`0001`, `0003` and `0004` together and treat a build without `0003` as unable to follow the
|
||||||
|
current chain.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Start it
|
||||||
|
|
||||||
|
```bash
|
||||||
|
besu \
|
||||||
|
--genesis-file=/path/to/aere-node/genesis.json \
|
||||||
|
--data-path=/path/to/data \
|
||||||
|
--network-id=2800 \
|
||||||
|
--sync-mode=FULL \
|
||||||
|
--data-storage-format=BONSAI \
|
||||||
|
--bootnodes=<the enode you were given> \
|
||||||
|
--p2p-port=30303 \
|
||||||
|
--rpc-http-enabled --rpc-http-port=8545 \
|
||||||
|
--rpc-http-api=ETH,NET,WEB3,QBFT \
|
||||||
|
--min-gas-price=0
|
||||||
|
```
|
||||||
|
|
||||||
|
Bootnodes are deliberately NOT published in this repository yet. The network entry points
|
||||||
|
available today are consensus or origin hosts, and this project does not print the addresses
|
||||||
|
of its own machines in public documents; a dedicated public bootnode, on a host that serves
|
||||||
|
nothing else, is the planned replacement, and this paragraph will then carry its enode. Until
|
||||||
|
then, write to office@aere.network with the subject "bootnode" and you will receive a current
|
||||||
|
enode by return. Everything else on this page works without one; discovery is the only step
|
||||||
|
that needs it.
|
||||||
|
|
||||||
|
`--sync-mode=FULL` is deliberate. Chain 2800 runs QBFT with a half second block period, so the head
|
||||||
|
is around twelve million blocks and climbing by two per second. Full sync from block 0 is the mode
|
||||||
|
that actually verifies the history we publish, which is the point of this repository. Snap sync
|
||||||
|
against a QBFT chain trusts a peer for the state and verifies far less.
|
||||||
|
|
||||||
|
`--min-gas-price=0` matches the network. Chain 2800 has a real 1 Gwei base fee from block
|
||||||
|
10,141,734, but the minimum gas price a node will accept into its own pool is a local policy and the
|
||||||
|
Foundation nodes run it at zero.
|
||||||
|
|
||||||
|
Outbound and inbound TCP and UDP on your p2p port must be open. Discovery is UDP; a TCP only
|
||||||
|
firewall gives you a node that dials out and is never dialled back.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Check that you are on the right chain, before you trust anything else
|
||||||
|
|
||||||
|
Two facts settle it. Run these against your own node once it is up.
|
||||||
|
|
||||||
|
**1. Your block 0 must be the network's block 0.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST http://127.0.0.1:8545 -H 'content-type: application/json' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0x0",false]}' \
|
||||||
|
| grep -o '"hash":"0x[0-9a-f]*"'
|
||||||
|
```
|
||||||
|
|
||||||
|
Expected, and this is the whole test:
|
||||||
|
|
||||||
|
```
|
||||||
|
0xd86d57a899cbfa580669f0e1c7cd4ae5f525247c3c823f8f75df176a0c5d7f1a
|
||||||
|
```
|
||||||
|
|
||||||
|
That hash covers every consensus relevant field in `genesis.json`, including the state root of the
|
||||||
|
six genesis accounts. If it matches, your genesis file is the network's genesis file and no further
|
||||||
|
comparison of individual fields is needed. If it does not match, your node will never peer, and no
|
||||||
|
amount of correct bootnodes will help.
|
||||||
|
|
||||||
|
Compare against the public endpoints, which are separate machines with separate operators of the
|
||||||
|
same file:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST https://rpc.aere.network -H 'content-type: application/json' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0x0",false]}'
|
||||||
|
curl -s -X POST https://rpc2.aere.network -H 'content-type: application/json' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"eth_getBlockByNumber","params":["0x0",false]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. You must have peers.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -s -X POST http://127.0.0.1:8545 -H 'content-type: application/json' \
|
||||||
|
-d '{"jsonrpc":"2.0","id":1,"method":"net_peerCount","params":[]}'
|
||||||
|
```
|
||||||
|
|
||||||
|
A nonzero answer means discovery worked. Zero after a few minutes means either your UDP port is
|
||||||
|
closed or the bootnode you were given is down; a plain TCP connect to its address distinguishes
|
||||||
|
the two.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What the two bootnodes are, and what they are not
|
||||||
|
|
||||||
|
They are two full nodes that are **not** in the validator set. Chain 2800 seals blocks with seven
|
||||||
|
QBFT validators, and none of the seven is listed here, on purpose. Publishing a validator's p2p
|
||||||
|
address hands an attacker a target whose downtime costs the network consensus headroom, which is why
|
||||||
|
sentry style architectures exist. The two nodes above carry no consensus responsibility: if both are
|
||||||
|
taken down, new nodes cannot bootstrap until they are replaced, and block production is unaffected.
|
||||||
|
|
||||||
|
A written address is not a live address. This file cannot prove the bootnodes are up at the moment
|
||||||
|
you read it; only your own `net_peerCount` can.
|
||||||
|
|
||||||
|
Both were reachable and serving blocks when this file was written. Both are Foundation operated, so
|
||||||
|
this is one operator's word for two addresses. That is a real centralisation fact about chain 2800
|
||||||
|
today and not a documentation gap.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Measured, 2026-08-03
|
||||||
|
|
||||||
|
The recipe on this page was executed rather than written. A Besu node with an **empty data
|
||||||
|
directory** was started from exactly this `genesis.json` and exactly these two bootnode URLs, on a
|
||||||
|
machine that is not a validator, with `--sync-mode=FULL` and no static nodes, no other peer hints
|
||||||
|
and no copied database.
|
||||||
|
|
||||||
|
- Its own block 0 came out as
|
||||||
|
`0xd86d57a899cbfa580669f0e1c7cd4ae5f525247c3c823f8f75df176a0c5d7f1a`, which is the live chain's
|
||||||
|
block 0. That hash covers the state root, so the six accounts in `alloc` are the network's down to
|
||||||
|
the last wei, and so is every header field in the file.
|
||||||
|
- It reached **11 peers** knowing nothing but the two enode URLs above.
|
||||||
|
- It imported from block 0 to **block 2,221,580** in about thirty minutes, with **zero** rejected
|
||||||
|
blocks, which carries it through the sub-second block period change at roughly 2,137,652 and out
|
||||||
|
the other side.
|
||||||
|
|
||||||
|
The honest limits on that run, stated because they are the difference between this section and an
|
||||||
|
advertisement:
|
||||||
|
|
||||||
|
- It was stopped at ~2.2 million rather than carried to the head, so it never reached the precompile
|
||||||
|
fork at 9,189,161 or the base fee floor at 10,141,734. **"Reaches the current head" is not
|
||||||
|
measured.**
|
||||||
|
- It ran the Foundation's build of the fork, not a build a third party made from `patches/`. That
|
||||||
|
those patches build, and that the built precompiles answer the NIST vectors, is measured
|
||||||
|
separately in `README.md`; that the two together sync to the head is not.
|
||||||
|
- Nothing here proves the bootnodes will be up when you read this.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## A number in this file that the chain does not agree with
|
||||||
|
|
||||||
|
`config.transitions.qbft[0].block` reads **2138451**. That is the height at which the file says the
|
||||||
|
block period drops from one second to half a second. The chain says otherwise. Sampling header
|
||||||
|
timestamps on the public endpoints puts the change just after **2,137,652**. Measured spans of
|
||||||
|
twenty blocks: from 2,137,600 the twenty blocks take 20 s, from 2,137,656 they take 15 s, from
|
||||||
|
2,137,657 they take 12 s, and from 2,137,700 they take a flat 10 s, which is 500 ms a block and
|
||||||
|
stays there through 2,138,400. The published 2138451 is roughly eight hundred blocks late and
|
||||||
|
describes a boundary that is not in the data.
|
||||||
|
|
||||||
|
It is published anyway, unaltered, because this file is the file the network runs and its value as
|
||||||
|
evidence comes from being exactly that. Two things make the discrepancy harmless to you rather than
|
||||||
|
merely tolerated: the field only governs how fast a proposer may seal, so it has no effect on a node
|
||||||
|
that follows; and it was measured, on the sync run described above, that a node carrying this exact
|
||||||
|
value imports the blocks either side of both numbers without rejecting one.
|
||||||
|
|
||||||
|
Correcting it means editing a file on live validators, which is a change to running consensus
|
||||||
|
infrastructure and is not made as a side effect of publishing a document.
|
||||||
|
|
||||||
|
## A note on the `comment` fields in `alloc`
|
||||||
|
|
||||||
|
The six genesis accounts carry `comment` strings. No client reads them; they are not consensus data
|
||||||
|
and they are inside the file only because they have always been. Two of them are wrong and are left
|
||||||
|
uncorrected here rather than quietly edited, because this file is published byte for byte as the
|
||||||
|
running nodes hold it: the dash characters are mangled, and the 1,400,000,000 AERE account is
|
||||||
|
labelled "Mining Reserve" although chain 2800 has no mining and never has. It is the staking and
|
||||||
|
emissions reserve. Correcting the text means editing a file on live nodes, which is a change to
|
||||||
|
running infrastructure and is not made as a side effect of a documentation fix.
|
||||||
77
genesis.json
Normal file
77
genesis.json
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"chainId": 2800,
|
||||||
|
"homesteadBlock": 0,
|
||||||
|
"eip150Block": 0,
|
||||||
|
"eip155Block": 0,
|
||||||
|
"eip158Block": 0,
|
||||||
|
"byzantiumBlock": 0,
|
||||||
|
"constantinopleBlock": 0,
|
||||||
|
"petersburgBlock": 0,
|
||||||
|
"istanbulBlock": 0,
|
||||||
|
"muirGlacierBlock": 0,
|
||||||
|
"berlinBlock": 0,
|
||||||
|
"londonBlock": 0,
|
||||||
|
"shanghaiTime": 0,
|
||||||
|
"qbft": {
|
||||||
|
"blockperiodseconds": 1,
|
||||||
|
"epochlength": 30000,
|
||||||
|
"requesttimeoutseconds": 4
|
||||||
|
},
|
||||||
|
"cancunTime": 1780189051,
|
||||||
|
"pragueTime": 1780189051,
|
||||||
|
"osakaTime": 1780220351,
|
||||||
|
"futureEipsTime": 1783820272,
|
||||||
|
"transitions": {
|
||||||
|
"qbft": [
|
||||||
|
{
|
||||||
|
"block": 2138451,
|
||||||
|
"xblockperiodmilliseconds": 500
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pqRegistryHash": [
|
||||||
|
{
|
||||||
|
"block": 13014000,
|
||||||
|
"hash": "0xa96ac96dcd4f1671aec8b6063cee17a3341314c92e1dd2623bc6500b7e28b0cb"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"block": 13600000,
|
||||||
|
"hash": "0x5e6ac058b22beaa895469671308548dfd44fbaa9ca7ea30b3dafa950c359b9b3"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"nonce": "0x0",
|
||||||
|
"timestamp": "0x69fbd960",
|
||||||
|
"gasLimit": "0x1fffffffffffff",
|
||||||
|
"difficulty": "0x1",
|
||||||
|
"mixHash": "0x63746963616c2062797a616e74696e65206661756c7420746f6c6572616e6365",
|
||||||
|
"coinbase": "0x0000000000000000000000000000000000000000",
|
||||||
|
"extraData": "0xf865a00000000000000000000000000000000000000000000000000000000000000000f83f94b5e768cb3117ea25175f51aa956b48691025c2a894f73bbbd26a82dbc769066550d8d4585eab2fc00d944bf6f91d84b37454544279cba152581ed6820044c080c0",
|
||||||
|
"alloc": {
|
||||||
|
"0xaee2f3989f0AB23296Fa3b92247fe67587141311": {
|
||||||
|
"balance": "0x52b7d2dcc80cd2e4000000",
|
||||||
|
"comment": "Strategic Investor \u00e2\u20ac\u201d 100,000,000 AERE (3.57% of supply)"
|
||||||
|
},
|
||||||
|
"0x0243A4f47D44b40b65D33f20329dE20D00c6f3C3": {
|
||||||
|
"balance": "0x94e47b8d68171534000000",
|
||||||
|
"comment": "Foundation \u00e2\u20ac\u201d 180,000,000 AERE (operations + signing wallet)"
|
||||||
|
},
|
||||||
|
"0x038f59A40ceeCd599A4588E4B0ff4642a0fbfFB8": {
|
||||||
|
"balance": "0x4860d8812f0b38878000000",
|
||||||
|
"comment": "Mining Reserve \u00e2\u20ac\u201d 1,400,000,000 AERE (50% of supply, mining emissions)"
|
||||||
|
},
|
||||||
|
"0xB6a364F47d21DC2CbEB803565c111c1026e11C75": {
|
||||||
|
"balance": "0x1cf389cd46047d030000000",
|
||||||
|
"comment": "Ecosystem Reserve \u00e2\u20ac\u201d 560,000,000 AERE (20% of supply, grants + partnerships)"
|
||||||
|
},
|
||||||
|
"0x7968C438204a78B4e032fcFFd9A56Edb15fdCCdf": {
|
||||||
|
"balance": "0x15b6a759f4835dc24000000",
|
||||||
|
"comment": "Team Reserve \u00e2\u20ac\u201d 420,000,000 AERE (15% of supply, team allocations)"
|
||||||
|
},
|
||||||
|
"0x261913fA73D6F109382F1aE98Ff6822ff03628B1": {
|
||||||
|
"balance": "0x73ce27351811f40c000000",
|
||||||
|
"comment": "Airdrop Reserve \u00e2\u20ac\u201d 140,000,000 AERE (5% of supply, community airdrops)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
223
patches/0004-aere-basefee-floor.patch
Normal file
223
patches/0004-aere-basefee-floor.patch
Normal file
@ -0,0 +1,223 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Aere Network <node@aere.network>
|
||||||
|
Date: Mon, 3 Aug 2026 04:00:00 +0300
|
||||||
|
Subject: [PATCH] Aere Network: fork-gated consensus floor for the EIP-1559
|
||||||
|
base fee
|
||||||
|
|
||||||
|
Adds a real consensus minimum base fee to LondonFeeMarket, gated on a fork
|
||||||
|
block. When the block number reaches aere.basefee.floor.forkBlock, the computed
|
||||||
|
EIP-1559 base fee is clamped to max(computed, aere.basefee.floor.value).
|
||||||
|
|
||||||
|
computeBaseFee is used for BOTH block production and block validation, so this
|
||||||
|
is a genuine consensus rule and not a display trick: every node must carry the
|
||||||
|
change, and a node without it computes the old, lower base fee and rejects the
|
||||||
|
floored block.
|
||||||
|
|
||||||
|
Default forkBlock is Long.MAX_VALUE, so with no configuration the behaviour is
|
||||||
|
identical to the unmodified file and pre-fork blocks validate unchanged.
|
||||||
|
|
||||||
|
NOT ACTIVE ON AERE NETWORK CHAIN 2800. No fork block has been set on mainnet.
|
||||||
|
Arming it is a governance decision that has not been taken.
|
||||||
|
|
||||||
|
Upstream-Status: Inappropriate [Aere Network specific consensus rule]
|
||||||
|
|
||||||
|
Modified upstream files. One file touched by this patch is a modified copy of a
|
||||||
|
Hyperledger Besu source, not new work by Aere Network:
|
||||||
|
|
||||||
|
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java
|
||||||
|
|
||||||
|
Aere Network changed it, against upstream commit
|
||||||
|
d2032017bb3b8cb215a97303980a1e4a643f7180. Its original "Copyright ConsenSys AG"
|
||||||
|
header is kept unchanged, which is what Apache License 2.0 section 4(c)
|
||||||
|
requires, and this patch adds below it a separate "Modifications Copyright"
|
||||||
|
block naming exactly what was changed. That in-file block is the notice
|
||||||
|
required by Apache License 2.0 section 4(b). It travels inside the diff, so a
|
||||||
|
tree with this patch applied carries the notice whether you used git am or git
|
||||||
|
apply. This patch creates no new files.
|
||||||
|
|
||||||
|
Note that the copyright holder on this file is ConsenSys AG, not "contributors
|
||||||
|
to Hyperledger Besu" as on the files touched by patches 0001 and 0002. Both
|
||||||
|
holders are named in NOTICE, as Apache License 2.0 section 4(d) requires.
|
||||||
|
---
|
||||||
|
.../mainnet/feemarket/LondonFeeMarket.java | 48 +++++++++++++++++--
|
||||||
|
1 file changed, 45 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java
|
||||||
|
index 0ee4f74..83a639c 100644
|
||||||
|
--- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java
|
||||||
|
+++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/feemarket/LondonFeeMarket.java
|
||||||
|
@@ -1,56 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright ConsenSys AG.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
|
||||||
|
* the License. You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
|
||||||
|
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
||||||
|
* specific language governing permissions and limitations under the License.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
+ * Modifications Copyright 2026 Aere Network.
|
||||||
|
+ *
|
||||||
|
+ * This file was changed by Aere Network: a fork-gated consensus minimum for the
|
||||||
|
+ * EIP-1559 base fee was added. Two system properties configure it
|
||||||
|
+ * (aere.basefee.floor.forkBlock, aere.basefee.floor.value), a private helper
|
||||||
|
+ * applyAereBaseFeeFloor was added, and the three return paths of computeBaseFee
|
||||||
|
+ * now pass through that helper. The default fork block is Long.MAX_VALUE, so an
|
||||||
|
+ * unconfigured node behaves exactly as the unmodified file does. Nothing upstream
|
||||||
|
+ * was removed or rewritten.
|
||||||
|
+ *
|
||||||
|
+ * The unmodified original is Hyperledger Besu commit
|
||||||
|
+ * d2032017bb3b8cb215a97303980a1e4a643f7180. The upstream copyright header above is
|
||||||
|
+ * left exactly as it was found.
|
||||||
|
+ *
|
||||||
|
+ * This notice is required by Apache License 2.0 section 4(b).
|
||||||
|
+ */
|
||||||
|
package org.hyperledger.besu.ethereum.mainnet.feemarket;
|
||||||
|
|
||||||
|
import org.hyperledger.besu.config.GenesisConfig;
|
||||||
|
import org.hyperledger.besu.datatypes.Wei;
|
||||||
|
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||||
|
import org.hyperledger.besu.ethereum.core.feemarket.TransactionPriceCalculator;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.apache.tuweni.units.bigints.UInt256s;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
public class LondonFeeMarket implements BaseFeeMarket {
|
||||||
|
private static final Logger LOG = LoggerFactory.getLogger(LondonFeeMarket.class);
|
||||||
|
|
||||||
|
static final Wei DEFAULT_BASEFEE_INITIAL_VALUE = GenesisConfig.BASEFEE_AT_GENESIS_DEFAULT_VALUE;
|
||||||
|
static final long DEFAULT_BASEFEE_MAX_CHANGE_DENOMINATOR = 8L;
|
||||||
|
static final long DEFAULT_SLACK_COEFFICIENT = 2L;
|
||||||
|
|
||||||
|
private static final Wei DEFAULT_BASEFEE_FLOOR = Wei.of(7L);
|
||||||
|
|
||||||
|
+ // === AERE base-fee floor fork (fork-gated, system-property configured) ===
|
||||||
|
+ // A real consensus minimum base fee, not a display trick. When the running block
|
||||||
|
+ // number reaches AERE_BASEFEE_FLOOR_FORK_BLOCK, the EIP-1559 base fee is clamped to
|
||||||
|
+ // max(computed, AERE_BASEFEE_FLOOR_VALUE). Because computeBaseFee is used for BOTH
|
||||||
|
+ // block production AND block validation, this is a genuine consensus rule: every node
|
||||||
|
+ // must agree, and a node without this change computes the old (lower) base fee and
|
||||||
|
+ // rejects the floored block. Default forkBlock = Long.MAX_VALUE => never active =>
|
||||||
|
+ // byte-identical behavior to stock Besu (pre-fork blocks are unchanged).
|
||||||
|
+ private static final long AERE_BASEFEE_FLOOR_FORK_BLOCK =
|
||||||
|
+ Long.getLong("aere.basefee.floor.forkBlock", Long.MAX_VALUE);
|
||||||
|
+ private static final Wei AERE_BASEFEE_FLOOR_VALUE =
|
||||||
|
+ Wei.of(Long.getLong("aere.basefee.floor.value", 1_000_000_000L));
|
||||||
|
+
|
||||||
|
protected final Wei baseFeeInitialValue;
|
||||||
|
private final long londonForkBlockNumber;
|
||||||
|
private final TransactionPriceCalculator txPriceCalculator;
|
||||||
|
private final Wei baseFeeFloor;
|
||||||
|
|
||||||
|
LondonFeeMarket(final long londonForkBlockNumber, final Optional<Wei> baseFeePerGasOverride) {
|
||||||
|
this(TransactionPriceCalculator.eip1559(), londonForkBlockNumber, baseFeePerGasOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
LondonFeeMarket(
|
||||||
|
final TransactionPriceCalculator txPriceCalculator,
|
||||||
|
final long londonForkBlockNumber,
|
||||||
|
final Optional<Wei> baseFeePerGasOverride) {
|
||||||
|
this.txPriceCalculator = txPriceCalculator;
|
||||||
|
this.londonForkBlockNumber = londonForkBlockNumber;
|
||||||
|
this.baseFeeInitialValue = baseFeePerGasOverride.orElse(DEFAULT_BASEFEE_INITIAL_VALUE);
|
||||||
|
this.baseFeeFloor = baseFeeInitialValue.isZero() ? Wei.ZERO : DEFAULT_BASEFEE_FLOOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@@ -66,72 +97,83 @@ public class LondonFeeMarket implements BaseFeeMarket {
|
||||||
|
@Override
|
||||||
|
public long getSlackCoefficient() {
|
||||||
|
return DEFAULT_SLACK_COEFFICIENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionPriceCalculator getTransactionPriceCalculator() {
|
||||||
|
return txPriceCalculator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean satisfiesFloorTxFee(final Transaction txn) {
|
||||||
|
// ensure effective baseFee is at least above floor
|
||||||
|
return txn.getGasPrice()
|
||||||
|
.map(Optional::of)
|
||||||
|
.orElse(txn.getMaxFeePerGas())
|
||||||
|
.filter(fee -> fee.greaterOrEqualThan(baseFeeFloor))
|
||||||
|
.isPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // AERE base-fee floor fork: clamp the computed base fee to the floor once the fork
|
||||||
|
+ // block is reached. No-op before the fork block (and always a no-op when the fork is
|
||||||
|
+ // unset, i.e. forkBlock = Long.MAX_VALUE), so pre-fork blocks validate byte-identically.
|
||||||
|
+ private Wei applyAereBaseFeeFloor(final long blockNumber, final Wei fee) {
|
||||||
|
+ if (blockNumber >= AERE_BASEFEE_FLOOR_FORK_BLOCK
|
||||||
|
+ && !fee.greaterOrEqualThan(AERE_BASEFEE_FLOOR_VALUE)) {
|
||||||
|
+ return AERE_BASEFEE_FLOOR_VALUE;
|
||||||
|
+ }
|
||||||
|
+ return fee;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
@Override
|
||||||
|
public Wei computeBaseFee(
|
||||||
|
final long blockNumber,
|
||||||
|
final Wei parentBaseFee,
|
||||||
|
final long parentBlockGasUsed,
|
||||||
|
final long targetGasUsed) {
|
||||||
|
if (londonForkBlockNumber == blockNumber) {
|
||||||
|
- return getInitialBasefee();
|
||||||
|
+ return applyAereBaseFeeFloor(blockNumber, getInitialBasefee());
|
||||||
|
}
|
||||||
|
|
||||||
|
long gasDelta;
|
||||||
|
Wei feeDelta, baseFee;
|
||||||
|
if (parentBlockGasUsed == targetGasUsed) {
|
||||||
|
- return parentBaseFee;
|
||||||
|
+ return applyAereBaseFeeFloor(blockNumber, parentBaseFee);
|
||||||
|
} else if (parentBlockGasUsed > targetGasUsed) {
|
||||||
|
gasDelta = parentBlockGasUsed - targetGasUsed;
|
||||||
|
final long denominator = getBasefeeMaxChangeDenominator();
|
||||||
|
feeDelta =
|
||||||
|
UInt256s.max(
|
||||||
|
parentBaseFee.multiply(gasDelta).divide(targetGasUsed).divide(denominator), Wei.ONE);
|
||||||
|
baseFee = parentBaseFee.add(feeDelta);
|
||||||
|
} else {
|
||||||
|
gasDelta = targetGasUsed - parentBlockGasUsed;
|
||||||
|
final long denominator = getBasefeeMaxChangeDenominator();
|
||||||
|
feeDelta = parentBaseFee.multiply(gasDelta).divide(targetGasUsed).divide(denominator);
|
||||||
|
baseFee = parentBaseFee.subtract(feeDelta);
|
||||||
|
}
|
||||||
|
LOG.trace(
|
||||||
|
"block #{} parentBaseFee: {} parentGasUsed: {} parentGasTarget: {} baseFee: {}",
|
||||||
|
blockNumber,
|
||||||
|
parentBaseFee,
|
||||||
|
parentBlockGasUsed,
|
||||||
|
targetGasUsed,
|
||||||
|
baseFee);
|
||||||
|
- return baseFee;
|
||||||
|
+ return applyAereBaseFeeFloor(blockNumber, baseFee);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidationMode baseFeeValidationMode(final long blockNumber) {
|
||||||
|
return londonForkBlockNumber == blockNumber ? ValidationMode.INITIAL : ValidationMode.ONGOING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ValidationMode gasLimitValidationMode(final long blockNumber) {
|
||||||
|
return londonForkBlockNumber == blockNumber ? ValidationMode.INITIAL : ValidationMode.ONGOING;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBeforeForkBlock(final long blockNumber) {
|
||||||
|
return londonForkBlockNumber > blockNumber;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user