Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/hivechain: support for newer forks, more chain outputs #909

Merged
merged 11 commits into from
Oct 19, 2023
68 changes: 68 additions & 0 deletions cmd/hivechain/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# hivechain

Hivechain creates a non-empty blockchain for testing purposes. To facilitate good tests,
the created chain excercises many protocol features, including:

- different types of transactions
- diverse set of contracts with interesting storage, code, etc.
- contracts to create known log events
- non-transaction chain modifications: coinbase fee payments, uncles, withdrawals...

## Running hivechain

Here is an example command line invocation of the tool:

hivechain generate -fork-interval 6 -tx-interval 1 -length 500 -outdir chain -outputs genesis,chain,headfcu

The command creates a 500-block chain where a new fork gets enabled every six blocks, and
every block contains one 'modification' (i.e. transaction). A number of output files will
be created in the `chain/` directory:

- `genesis.json` contains the genesis block specification
- `chain.rlp` has the blocks in binary RLP format
- `headfcu.json` contains an Engine API request that sends the head block to a client

To see all generator options, run:

hivechain generate -help

## -outputs

Different kinds of output files can be created based on the generated chain. The available
output formats are documented below.

### accounts

Creates `accounts.json` containing accounts and corresponding private keys.

### chain, powchain

`chain` creates `chain.rlp` containing the chain blocks.

`powchain` creates `powchain.rlp` containing only the pre-merge blocks.

### fcu, headfcu, newpayload

`fcu.json` is a JSON array of forkchoiceUpdated requests for all post-merge blocks.

`headfcu.json` is a request for just the head block. This is useful for triggering a sync in the client.

`newpayload.json` is a JSON array of newPayload requests for post-merge blocks.

### genesis

This writes the `genesis.json` file containing a go-ethereum style genesis spec. Note
this file includes the fork block numbers/timestamps.

### headblock

This creates `headblock.json` with a dump of the head header.

### headstate

This writes `headstate.json`, a dump of the complete state of the head block.

### txinfo

The `txinfo.json` file contains an object with a key for each block modifier, and the
value being information about the activity of the modifier.
99 changes: 99 additions & 0 deletions cmd/hivechain/accounts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package main

import (
"crypto/ecdsa"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

var knownAccounts = []genAccount{
{
key: mustParseKey("4552dbe6ca4699322b5d923d0c9bcdd24644f5db8bf89a085b67c6c49b8a1b91"),
addr: common.HexToAddress("0x7435ed30A8b4AEb0877CEf0c6E8cFFe834eb865f"),
},
{
key: mustParseKey("f6a8f1603b8368f3ca373292b7310c53bec7b508aecacd442554ebc1c5d0c856"),
addr: common.HexToAddress("0x84E75c28348fB86AceA1A93a39426d7D60f4CC46"),
},
{
key: mustParseKey("6e1e16a9c15641c73bf6e237f9293ab1d4e7c12b9adf83cfc94bcf969670f72d"),
addr: common.HexToAddress("0x4ddE844b71bcdf95512Fb4Dc94e84FB67b512eD8"),
},
{
key: mustParseKey("fc39d1c9ddbba176d806ebb42d7460189fe56ca163ad3eb6143bfc6beb6f6f72"),
addr: common.HexToAddress("0xd803681E487E6AC18053aFc5a6cD813c86Ec3E4D"),
},
{
key: mustParseKey("a88293fefc623644969e2ce6919fb0dbd0fd64f640293b4bf7e1a81c97e7fc7f"),
addr: common.HexToAddress("0x4a0f1452281bCec5bd90c3dce6162a5995bfe9df"),
},
{
key: mustParseKey("457075f6822ac29481154792f65c5f1ec335b4fea9ca20f3fea8fa1d78a12c68"),
addr: common.HexToAddress("0x14e46043e63D0E3cdcf2530519f4cFAf35058Cb2"),
},
{
key: mustParseKey("9ee3fd550664b246ad7cdba07162dd25530a3b1d51476dd1d85bbc29f0592684"),
addr: common.HexToAddress("0xE7d13f7Aa2A838D24c59b40186a0aCa1e21CffCC"),
},
{
key: mustParseKey("865898edcf43206d138c93f1bbd86311f4657b057658558888aa5ac4309626a6"),
addr: common.HexToAddress("0x16c57eDF7Fa9D9525378B0b81Bf8A3cEd0620C1c"),
},
{
key: mustParseKey("19168cd7767604b3d19b99dc3da1302b9ccb6ee9ad61660859e07acd4a2625dd"),
addr: common.HexToAddress("0x2D389075BE5be9F2246Ad654cE152cF05990b209"),
},
{
key: mustParseKey("ee7f7875d826d7443ccc5c174e38b2c436095018774248a8074ee92d8914dcdb"),
addr: common.HexToAddress("0x1F4924B14F34e24159387C0A4CdBaa32f3DDb0cF"),
},
{
key: mustParseKey("bfcd0e032489319f4e5ca03e643b2025db624be6cf99cbfed90c4502e3754850"),
addr: common.HexToAddress("0x0c2c51a0990AeE1d73C1228de158688341557508"),
},
{
key: mustParseKey("41be4e00aac79f7ffbb3455053ec05e971645440d594c047cdcc56a3c7458bd6"),
addr: common.HexToAddress("0x5f552da00dFB4d3749D9e62dCeE3c918855A86A0"),
},
{
key: mustParseKey("71aa7d299c7607dabfc3d0e5213d612b5e4a97455b596c2f642daac43fa5eeaa"),
addr: common.HexToAddress("0x3aE75c08b4c907EB63a8960c45B86E1e9ab6123c"),
},
{
key: mustParseKey("c825f31cd8792851e33a290b3d749e553983111fc1f36dfbbdb45f101973f6a9"),
addr: common.HexToAddress("0x654aa64f5FbEFb84c270eC74211B81cA8C44A72e"),
},
{
key: mustParseKey("8d0faa04ae0f9bc3cd4c890aa025d5f40916f4729538b19471c0beefe11d9e19"),
addr: common.HexToAddress("0x717f8AA2b982BeE0e29f573D31Df288663e1Ce16"),
},
{
key: mustParseKey("47f666f20e2175606355acec0ea1b37870c15e5797e962340da7ad7972a537e8"),
addr: common.HexToAddress("0x4340Ee1b812ACB40a1eb561C019c327b243b92Df"),
},
{
key: mustParseKey("8d56bcbcf2c1b7109e1396a28d7a0234e33544ade74ea32c460ce4a443b239b1"),
addr: common.HexToAddress("0xC7B99a164Efd027a93f147376Cc7DA7C67c6bbE0"),
},
{
key: mustParseKey("34391cbbf06956bb506f45ec179cdd84df526aa364e27bbde65db9c15d866d00"),
addr: common.HexToAddress("0x83C7e323d189f18725ac510004fdC2941F8C4A78"),
},
{
key: mustParseKey("25e6ce8611cefb5cd338aeaa9292ed2139714668d123a4fb156cabb42051b5b7"),
addr: common.HexToAddress("0x1F5BDe34B4afC686f136c7a3CB6EC376F7357759"),
},
{
key: mustParseKey("14cdde09d1640eb8c3cda063891b0453073f57719583381ff78811efa6d4199f"),
addr: common.HexToAddress("0xedA8645bA6948855E3B3cD596bbB07596d59c603"),
},
}

func mustParseKey(s string) *ecdsa.PrivateKey {
key, err := crypto.HexToECDSA(s)
if err != nil {
panic(err)
}
return key
}
Binary file added cmd/hivechain/bytecode/callenv.bin
Binary file not shown.
Binary file added cmd/hivechain/bytecode/callme.bin
Binary file not shown.
Binary file added cmd/hivechain/bytecode/callrevert.bin
Binary file not shown.
Binary file added cmd/hivechain/bytecode/deployer.bin
Binary file not shown.
Binary file added cmd/hivechain/bytecode/gencode.bin
Binary file not shown.
Binary file added cmd/hivechain/bytecode/genlogs.bin
Binary file not shown.
1 change: 1 addition & 0 deletions cmd/hivechain/bytecode/genstorage.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
C[��U`Zaa�`W
11 changes: 11 additions & 0 deletions cmd/hivechain/compile.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh

set -xe

geas -bin -no-push0 contracts/deployer.eas > bytecode/deployer.bin
geas -bin -no-push0 contracts/callenv.eas > bytecode/callenv.bin
geas -bin -no-push0 contracts/callme.eas > bytecode/callme.bin
geas -bin -no-push0 contracts/callrevert.eas > bytecode/callrevert.bin
geas -bin -no-push0 contracts/genlogs.eas > bytecode/genlogs.bin
geas -bin -no-push0 contracts/gencode.eas > bytecode/gencode.bin
geas -bin -no-push0 contracts/genstorage.eas > bytecode/genstorage.bin
26 changes: 26 additions & 0 deletions cmd/hivechain/contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import _ "embed"

//go:embed bytecode/gencode.bin
var gencodeCode []byte

//go:embed bytecode/genlogs.bin
var genlogsCode []byte

//go:embed bytecode/genstorage.bin
var genstorageCode []byte

//go:embed bytecode/deployer.bin
var deployerCode []byte

//go:embed bytecode/callme.bin
var callmeCode []byte

//go:embed bytecode/callenv.bin
var callenvCode []byte

// //go:embed bytecode/deposit.bin
// var depositCode []byte
//
// const depositContractAddr = "0x00000000219ab540356cBB839Cbe05303d7705Fa"
36 changes: 36 additions & 0 deletions cmd/hivechain/contracts/callenv.eas
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
;;; -*- mode: asm -*-
;;; This contract returns EVM environment data.

#define %store { ; [value, ptr]
dup2 ; [ptr, value, ptr]
mstore ; [ptr]
push 32 ; [32, ptr]
add ; [newptr]
}

.start:
push 0 ; [ptr]

number ; [v, ptr]
%store ; [ptr]

chainid ; [v, ptr]
%store ; [ptr]

coinbase ; [v, ptr]
%store ; [ptr]

basefee ; [v, ptr]
%store ; [ptr]

difficulty ; [v, ptr]
%store ; [ptr]

origin ; [v, ptr]
%store ; [ptr]

callvalue ; [v, ptr]
%store ; [ptr]

push 0 ; [offset, ptr]
return ; []
40 changes: 40 additions & 0 deletions cmd/hivechain/contracts/callme.eas
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
;;; -*- mode: asm -*-
;;; This contract returns value `theOutput` if calldata is exactly equal to `theInput`.
;;; Otherwise, reverts with an error message.

#define theInput 0xff01
#define theOutput 0xffee

#define %revert(error) { ; []
push $error ; [value]
push 0 ; [offset, value]
mstore ; []
push .bytelen($error) ; [size]
push 32-.bytelen($error) ; [offset, size]
revert
}

.start:
calldatasize ; [size]
push .bytelen(theInput) ; [exp, iszero]
eq ; [size==exp]
jumpi @compare ; []
%revert("wrong-calldatasize")

compare:
push 0 ; [offset]
calldataload ; [calldata]
push 256-.bitlen(theInput) ; [shft, calldata]
shr ; [data]
push theInput ; [expv, data]
eq ; [data==expv]
jumpi @return ; []
%revert("wrong-calldata")

return:
push theOutput ; [v]
push 0 ; [offset, v]
mstore ; []
push .bytelen(theOutput) ; [size]
push 32-.bytelen(theInput) ; [offset, size]
return ; []
62 changes: 62 additions & 0 deletions cmd/hivechain/contracts/callrevert.eas
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
;;; -*- mode: asm -*-
;;; This contract is for testing two common Solidity revert encodings:
;;; panic(uint) and error(string).

;;; Dispatch
.start:
push 0 ; [offset]
calldataload ; [word]

;; if word == 0 revert with panic
iszero ; [word==0]
iszero ; [word!=0]
jumpi @error ; [word]

#define s_panic .selector("panic(uint)")
#define panicv 17

;;; Solidity ABI `panic(17)`
;;; Revert data layout:
;;;
;;; selector :: 4 || value :: 32
;;;
.panic:
push s_panic << (28*8) ; [sel]
push 0 ; [offset, sel]
mstore ; []
push 17 ; [panicv]
push 4 ; [offset, panicv]
mstore ; []

push 36 ; [length]
push 0 ; [offset, length]
revert ; []


#define s_error .selector("error(string)")
#define errmsg "user error"
#define errmsg_word errmsg << (255-.bitlen(errmsg))

;;; Solidity ABI error
;;;
;;; Revert data layout:
;;;
;;; selector :: 4 || 0x20 :: 32 || len :: 32 || data :: len
;;;
error:
push s_error << (28*8) ; [sel]
push 0 ; [offset, sel]
mstore ; []
push 0x20 ; [ptr]
push 4 ; [offset, ptr]
mstore ; []
push .bytelen(errmsg) ; [len]
push 36 ; [offset, len]
mstore ; []
push errmsg_word ; [data]
push 68 ; [offset, data]
mstore ; []

push 68 + .bytelen(errmsg) ; [length]
push 0 ; [offset, length]
revert
15 changes: 15 additions & 0 deletions cmd/hivechain/contracts/deployer.eas
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
;;; -*- mode: asm -*-
;;; puts any data after @.end into new contract

push @.end ; [end]
codesize ; [codesize, end]
sub ; [size]
;; copy to memory
dup1 ; [size, size]
push @.end ; [offset, size, size]
push 0 ; [destOffset, offset, size, size]
codecopy ; [size]
;; return memory content
push 0 ; [offset, size]
return ; []
.end:
Loading