Skip to content

Commit

Permalink
gen_genesis.go: wip on generating knot
Browse files Browse the repository at this point in the history
  • Loading branch information
alanorwick committed Aug 29, 2022
1 parent 5e203aa commit a8b9677
Show file tree
Hide file tree
Showing 7 changed files with 265 additions and 34 deletions.
56 changes: 56 additions & 0 deletions cmd/genesis/gen_genesis.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package main

import (
"compress/gzip"
"io"
"log"
"os"
"strings"

"github.com/spruce-solutions/go-quai/consensus/blake3"
"github.com/spruce-solutions/go-quai/core"
"github.com/spruce-solutions/go-quai/core/rawdb"
"github.com/spruce-solutions/go-quai/params"
)

func main() {
var (
testdb = rawdb.NewMemoryDatabase()
genesis = core.RopstenPrimeGenesisBlock().MustCommit(testdb)
fn = "test_knot.rlp"
)

blake3Config := blake3.Config{
MiningThreads: 0,
NotifyFull: true,
}

blake3Engine, err := blake3.New(blake3Config, nil, false)
if nil != err {
log.Fatal("Failed to create Blake3 engine: ", err)
}

blocks, _ := core.GenerateKnot(params.TestChainConfig, genesis, blake3Engine, testdb, 9, nil)

// Open the file handle and potentially wrap with a gzip stream
fh, err := os.OpenFile(fn, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, os.ModePerm)
if err != nil {
log.Panic("error opening file")
}
defer fh.Close()

var writer io.Writer = fh
if strings.HasSuffix(fn, ".gz") {
writer = gzip.NewWriter(writer)
defer writer.(*gzip.Writer).Close()
}

for _, block := range blocks {

if err := block.EncodeRLP(writer); err != nil {
log.Panic("error writing")
}
}

log.Println("Exported blockchain", "file", fn)
}
1 change: 1 addition & 0 deletions consensus/misc/gaslimit.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
// in relation to the parent gas limit.
func VerifyGaslimit(parentGasLimit, headerGasLimit uint64) error {
// Verify that the gas limit remains within allowed bounds
fmt.Println("Parent Gas", parentGasLimit, headerGasLimit)
diff := int64(parentGasLimit) - int64(headerGasLimit)
if diff < 0 {
diff *= -1
Expand Down
118 changes: 99 additions & 19 deletions core/chain_makers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ package core
import (
"errors"
"fmt"
"log"
"math/big"
"sync"

"github.com/spruce-solutions/go-quai/common"
"github.com/spruce-solutions/go-quai/consensus"
Expand Down Expand Up @@ -204,7 +206,8 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
chainreader := &fakeChainReader{config: config}
genblock := func(i int, parent *types.Block, statedb *state.StateDB) (*types.Block, types.Receipts) {
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
b.header = makeHeader(chainreader, parent, statedb, b.engine)
location := []byte{1, 1}
b.header = makeHeader(chainreader, parent, statedb, b.engine, location)

// Execute any user modifications to the block
if gen != nil {
Expand Down Expand Up @@ -239,7 +242,92 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
return blocks, receipts
}

func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine) *types.Header {
type knot struct {
block *types.Block
}

func GenerateKnot(config *params.ChainConfig, parent *types.Block, engine consensus.Engine, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
if config == nil {
config = params.TestChainConfig
}
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
chainreader := &fakeChainReader{config: config}

resultLoop := func(i int, k *knot, statedb *state.StateDB, results chan *types.Block, stop chan struct{}, wg *sync.WaitGroup) error {
for {
select {
case block := <-results:
context, err := engine.GetDifficultyOrder(block.Header())
if err != nil {
log.Println("Block mined has an invalid order")
}

if context == 0 {
log.Println("PRIME:", block.Header().Location, block.Header().Number, block.Header().Hash())
}

// Write state changes to db
root, err := statedb.Commit(config.IsEIP158(block.Number()))
if err != nil {
panic(fmt.Sprintf("state write error: %v", err))
}
if err := statedb.Database().TrieDB().Commit(root, false, nil); err != nil {
panic(fmt.Sprintf("trie write error: %v", err))
}

k.block = block

defer wg.Done()

return nil
}
}
}

genblock := func(i int, parent *types.Block, statedb *state.StateDB, location []byte, resultCh chan *types.Block, stopCh chan struct{}) {
b := &BlockGen{i: i, chain: blocks, parent: parent, statedb: statedb, config: config, engine: engine}
b.header = makeHeader(chainreader, parent, statedb, b.engine, location)

// Execute any user modifications to the block
if gen != nil {
gen(i, b)
}
if b.engine != nil {
// Finalize and seal the block
block, _ := b.engine.FinalizeAndAssemble(chainreader, b.header, statedb, b.txs, b.uncles, b.receipts)

// Mine the block
if err := engine.Seal(chainreader, block, resultCh, stopCh); err != nil {
log.Println("Block sealing failed", "err", err)
}
}
}

knot := &knot{
block: parent,
}

locations := [][]byte{[]byte{1, 1}, []byte{1, 2}, []byte{1, 3}, []byte{2, 1}, []byte{2, 2}, []byte{2, 3}, []byte{3, 1}, []byte{3, 2}, []byte{3, 3}}
for i := 0; i < len(locations); i++ {
statedb, err := state.New(parent.Root(), state.NewDatabase(db), nil)
if err != nil {
panic(err)
}
resultCh := make(chan *types.Block)
exitCh := make(chan struct{})

var wg sync.WaitGroup
wg.Add(1)
go resultLoop(i, knot, statedb, resultCh, exitCh, &wg)
genblock(i, parent, statedb, locations[i], resultCh, exitCh)
wg.Wait()
blocks[i] = knot.block
parent = knot.block
}
return blocks, receipts
}

func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.StateDB, engine consensus.Engine, location []byte) *types.Header {
var time uint64
if parent.Time() == 0 {
time = 10
Expand All @@ -264,32 +352,24 @@ func makeHeader(chain consensus.ChainReader, parent *types.Block, state *state.S
GasLimit: []uint64{0, 0, 0},
GasUsed: []uint64{0, 0, 0},
Extra: [][]byte{[]byte(nil), []byte(nil), []byte(nil)},
}
header.GasLimit[types.QuaiNetworkContext] = parent.GasLimit()

parentHeader := &types.Header{
Number: []*big.Int{big.NewInt(int64(1)), big.NewInt(int64(1)), big.NewInt(int64(1))},
Difficulty: []*big.Int{big.NewInt(1), big.NewInt(1), big.NewInt(1)},
UncleHash: types.EmptyUncleHash,
Time: time - 10,
Location: location,
}

if chain.Config().IsLondon(header.Number[types.QuaiNetworkContext]) {
if !chain.Config().IsLondon(parent.Number()) {
parentGasLimit := parent.GasLimit() * params.ElasticityMultiplier
header.GasLimit[types.QuaiNetworkContext] = CalcGasLimit(parentGasLimit, parent.GasUsed(), 0)
}
}
// Setting this to params.MinGasLimit for now since
header.GasLimit[types.QuaiNetworkContext] = params.MinGasLimit

parentHeader.Number[types.QuaiNetworkContext] = new(big.Int).Add(parent.Number(), common.Big1)
parentHeader.Difficulty[types.QuaiNetworkContext] = parent.Difficulty()
parentHeader.UncleHash[types.QuaiNetworkContext] = parent.UncleHash()
parentHeader := parent.Header()

header.Root[types.QuaiNetworkContext] = state.IntermediateRoot(chain.Config().IsEIP158(parent.Number()))
header.ParentHash[types.QuaiNetworkContext] = parent.Hash()
header.Coinbase[types.QuaiNetworkContext] = parent.Coinbase()
header.Difficulty[types.QuaiNetworkContext] = engine.CalcDifficulty(chain, time, parentHeader, types.QuaiNetworkContext)

header.Number[types.QuaiNetworkContext] = new(big.Int).Add(parent.Number(), common.Big1)
if len(parent.Header().Location) > 0 && header.Location[0] == parent.Header().Location[0] {
header.Number[types.QuaiNetworkContext+1] = new(big.Int).Add(parent.Header().Number[types.QuaiNetworkContext+1], common.Big1)

}

return header
}
Expand Down
37 changes: 22 additions & 15 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,16 @@ var errGenesisNoConfig = errors.New("genesis has no chain configuration")
// Genesis specifies the header fields, state of a genesis block. It also defines hard
// fork switch-over blocks through the chain configuration.
type Genesis struct {
Config *params.ChainConfig `json:"config"`
Nonce uint64 `json:"nonce"`
Timestamp uint64 `json:"timestamp"`
ExtraData [][]byte `json:"extraData"`
GasLimit []uint64 `json:"gasLimit" gencodec:"required"`
Difficulty []*big.Int `json:"difficulty" gencodec:"required"`
Coinbase []common.Address `json:"coinbase"`
Alloc GenesisAlloc `json:"alloc" gencodec:"required"`
Config *params.ChainConfig `json:"config"`
Knot []*types.Block `json:"knot"`

Nonce uint64 `json:"nonce"`
Timestamp uint64 `json:"timestamp"`
ExtraData [][]byte `json:"extraData"`
GasLimit []uint64 `json:"gasLimit" gencodec:"required"`
Difficulty []*big.Int `json:"difficulty" gencodec:"required"`
Coinbase []common.Address `json:"coinbase"`
Alloc GenesisAlloc `json:"alloc" gencodec:"required"`

// These fields are used for consensus tests. Please don't use them
// in actual genesis blocks.
Expand Down Expand Up @@ -288,7 +290,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
Root: []common.Hash{root, root, root},
}

if g.GasLimit[0] == 0 {
if len(g.GasLimit) == 0 {
head.GasLimit[types.QuaiNetworkContext] = params.GenesisGasLimit
}

Expand Down Expand Up @@ -350,8 +352,9 @@ func MainnetPrimeGenesisBlock() *Genesis {
return &Genesis{
Config: params.MainnetPrimeChainConfig,
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Coinbase: []common.Address{common.Address{}, common.Address{}, common.Address{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 60069,
Nonce: 60066,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
GasUsed: []uint64{0, 0, 0},
Expand All @@ -366,7 +369,7 @@ func MainnetRegionGenesisBlock(regionParams *params.ChainConfig) *Genesis {
Config: regionParams,
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 60069,
Nonce: 60066,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
GasUsed: []uint64{0, 0, 0},
Expand All @@ -381,7 +384,7 @@ func MainnetZoneGenesisBlock(zoneParams *params.ChainConfig) *Genesis {
Config: zoneParams,
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 60069,
Nonce: 60066,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
GasUsed: []uint64{0, 0, 0},
Expand All @@ -394,13 +397,15 @@ func MainnetZoneGenesisBlock(zoneParams *params.ChainConfig) *Genesis {
func RopstenPrimeGenesisBlock() *Genesis {
return &Genesis{
Config: params.RopstenPrimeChainConfig,
Knot: ReadKnot("test_knot.rlp"),
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Coinbase: []common.Address{common.Address{}, common.Address{}, common.Address{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 11,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
GasUsed: []uint64{0, 0, 0},
Difficulty: []*big.Int{big.NewInt(3448576), big.NewInt(1248576), big.NewInt(168576)},
Difficulty: []*big.Int{big.NewInt(30), big.NewInt(20), big.NewInt(10)},
Alloc: decodePrealloc(ropstenAllocData),
}
}
Expand All @@ -409,8 +414,9 @@ func RopstenPrimeGenesisBlock() *Genesis {
func RopstenRegionGenesisBlock(regionParams *params.ChainConfig) *Genesis {
return &Genesis{
Config: regionParams,
Knot: ReadKnot("test_knot.rlp"),
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Coinbase: []common.Address{common.Address{}, common.Address{}, common.Address{}}, Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 11,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
Expand All @@ -424,8 +430,9 @@ func RopstenRegionGenesisBlock(regionParams *params.ChainConfig) *Genesis {
func RopstenZoneGenesisBlock(zoneParams *params.ChainConfig) *Genesis {
return &Genesis{
Config: zoneParams,
Knot: ReadKnot("test_knot.rlp"),
ParentHash: []common.Hash{common.Hash{}, common.Hash{}, common.Hash{}},
Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Coinbase: []common.Address{common.Address{}, common.Address{}, common.Address{}}, Number: []*big.Int{big.NewInt(0), big.NewInt(0), big.NewInt(0)},
Nonce: 11,
ExtraData: [][]byte{hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa")},
GasLimit: []uint64{500000, 500000, 500000},
Expand Down
50 changes: 50 additions & 0 deletions core/knot.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package core

import (
"compress/gzip"
"fmt"
"io"
"os"
"strings"

"github.com/spruce-solutions/go-quai/core/types"
"github.com/spruce-solutions/go-quai/rlp"
)

func ReadKnot(chainfile string) []*types.Block {
// Load chain.rlp.
fmt.Println("Loading ReadKnot")
fh, err := os.Open(chainfile)
if err != nil {
fmt.Println("OPEN ERR 1", err)
return nil
}
defer fh.Close()
var reader io.Reader = fh
if strings.HasSuffix(chainfile, ".gz") {
if reader, err = gzip.NewReader(reader); err != nil {
fmt.Println("READER ERR 1", err)
return nil
}
}
stream := rlp.NewStream(reader, 0)
var blocks = make([]*types.Block, 1)
for i := 0; ; i++ {
var b types.Block
if err := stream.Decode(&b); err == io.EOF {
break
} else if err != nil {
fmt.Println("DECODE ERR 1", err)
return nil
}
if b.NumberU64() != uint64(i+1) {
fmt.Println("DECODE ERR 2", err)
return nil
}
blocks = append(blocks, &b)
}
for _, block := range blocks {
fmt.Println(block)
}
return blocks
}
Loading

0 comments on commit a8b9677

Please sign in to comment.