Skip to content

slave (M1): add slave node with config and genesis - #21

Merged
syntrust merged 16 commits into
goshard/basefrom
slave-m1
Jul 28, 2026
Merged

slave (M1): add slave node with config and genesis#21
syntrust merged 16 commits into
goshard/basefrom
slave-m1

Conversation

@syntrust

@syntrust syntrust commented Jun 23, 2026

Copy link
Copy Markdown

Boot a slave from a pyquarkchain-compatible cluster_config.json. The slave hosts the shards assigned to one slave identity (tracking issue #17).

  • cmd/slave: config (validate + print a normalized per-slave summary) and genesis (derive the root genesis block, hash byte-identical to pyquarkchain's GenesisManager.create_root_block())
  • qkc/config: cluster config loader (load.go, incl. ETH_CHAIN_ID consistency check) and checked-in singularity mainnet/devnet configs
  • qkc/genesis: root-block derivation
  • qkc/types: root block, token balances, helpers
  • Makefile: make slave target

Tests passed:

go test ./cmd/slave/...
go test ./qkc/...

Boot a slave from a pyquarkchain-compatible cluster_config.json. The slave
hosts the shards assigned to one slave identity and performs no network I/O
yet (tracking issue #17).

- cmd/slave: `config` (validate + print a normalized per-slave summary) and
  `genesis` (derive the root genesis block, hash byte-identical to
  pyquarkchain's GenesisManager.create_root_block())
- qkc/config: cluster config loader (load.go) and checked-in singularity
  mainnet/devnet configs
- qkc/genesis: root-block derivation
- qkc/types: root block, token balances, helpers
- Makefile: `make slave` target

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@syntrust
syntrust marked this pull request as ready for review June 24, 2026 02:33
@syntrust syntrust changed the title slave: add slave node (M1) with config and genesis slave (M1): add slave node with config and genesis Jun 24, 2026
@blockchaindevsh

Copy link
Copy Markdown

Looks like both this PR and #20 are adding duplicate content to qkc/types/?

@syntrust

Copy link
Copy Markdown
Author

Looks like both this PR and #20 are adding duplicate content to qkc/types/?

All types required to achieve the current milestone. We can use a refactor later before merging into the base.

Comment thread cmd/slave/main.go Outdated
app.Flags = slices.Concat(
[]cli.Flag{},
debug.Flags,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The expression slices.Concat([]cli.Flag{}, debug.Flags) is unnecessarily complex. Concatenating with an empty slice produces the same result as debug.Flags alone. Simplifying to debug.Flags removes one import ("slices") and makes the intent clearer.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in f92ba2f

Comment thread cmd/slave/configcmd.go
len(shard.Genesis.Alloc),
)
}
tw.Flush()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error returned by tw.Flush() is silently ignored.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignoring Flush() errors is consistent with surrounding Fprintf calls, both of which write targeting os.Stdout. This is common in geth, so it's acceptable and not a defect.

Comment thread qkc/types/tokenbalances.go Outdated
if v.Sign() == 0 {
continue
}
t.balances[k.Uint64()] = v

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate bigint(k) range before converting to uint64 to prevent truncation collisions.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 53d3f97

Comment thread qkc/types/tokenbalances.go Outdated
num, err := bb.GetUInt32()
if err != nil {
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add an entry count validation here to prevent potential OOM/DoS attacks from malicious data?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not really. Firstly, make does not pre-allocate according to num; secondly, every time an entry is read, it goes through the getBytes boundary check; plus, forcing an upper limit that pyquarkchain does not have will only create consensus disagreements.

@syntrust
syntrust requested a review from iteyelmp July 3, 2026 03:14
Comment thread qkc/types/tokenbalances.go Outdated
Comment thread qkc/types/tokenbalances.go Outdated
syntrust and others added 5 commits July 14, 2026 16:25
pyquarkchain always derives ETH_CHAIN_ID as BASE_ETH_CHAIN_ID + CHAIN_ID + 1
and overwrites any configured value with that derivation on load
(config.py:534); accept a configured value only when consistent with it.
pyquarkchain's arithmetic is unbounded, so BASE_ETH_CHAIN_ID + CHAIN_ID + 1
may exceed uint32; the uint32 sum wrapped silently (worst case to 0, which
reads as "absent" and passes any configured value).
Adopt the final CLI shape in the milestone that creates these files: newApp
assembles the app for tests, the cluster_config/node_id flags register globally
without Required (actions validate presence via loadClusterConfig), and only
non-networked debug flags are exposed, pinned by TestNoNetworkedDebugFlags.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stone

Drop the milestone markers and the not-yet-implemented tracker, adopt the final
fixtures/pyquarkchain cross-validation section (including the virtualenv note in
the singularity regeneration command), so later milestones only add sections.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The pyquarkchain derivation snippet already lives (with seal/serialize output)
in qkc/config/singularity/README.md; link to that section instead of carrying
a trimmed copy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
// overwrites any configured value with that derivation (config.py:534), so a
// present value is only accepted when consistent (checked in Validate). Zero
// means absent: real chain ids start at BASE_ETH_CHAIN_ID + 1 > 0.
EthChainID uint32 `json:"ETH_CHAIN_ID,omitempty"`

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ETH_CHAIN_ID is validated but never derived. When omitted (as in both singularity configs), chain and shard configs retain 0, while pyquarkchain sets BASE_ETH_CHAIN_ID + CHAIN_ID + 1. Normalize it before copying ChainConfig into shard configs, and distinguish omission from an explicit zero.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbfca80

Comment thread qkc/genesis/genesis.go Outdated
return nil, fmt.Errorf("genesis: ROOT.GENESIS.HASH_MERKLE_ROOT: %w", err)
}

difficulty := new(big.Int).SetUint64(g.Difficulty)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RootGenesis.Difficulty is uint64 and Nonce is uint32, but the QKC wire types are biguint and uint64. Valid pyquarkchain configs such as difficulty 2^64 or nonce 2^32 are rejected before hashing. Please preserve the wire ranges and add a Python golden case.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbfca80

Comment thread qkc/config/load.go
if shard.Genesis == nil {
return fmt.Errorf("full shard id 0x%08x has no GENESIS", id)
}
if shard.Genesis.RootHeight != root.Height {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Validate does not check shard-genesis hex fields. For example, EXTRA_DATA: "zz" is silently decoded as empty and slave config reports config OK; the failure is deferred until shard genesis creation. Strictly validate HASH_PREV_MINOR_BLOCK, HASH_MERKLE_ROOT, EXTRA_DATA, and ALLOC code/storage at load time.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbfca80

Comment thread qkc/config/load.go Outdated
if slave == nil {
continue
}
if len(slave.ChainMaskListForBackward) > 0 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

len(...) > 0 misses a present but empty CHAIN_MASK_LIST. With CHAIN_MASK_LIST: [] and no FULL_SHARD_ID_LIST, this config passes and reports zero shards. Track field presence and reject the legacy key whenever it is present.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbfca80

Comment thread qkc/types/tokenbalances.go Outdated
// TokenBalances maps a token id to a balance. It implements serialize.Serializable
// so it can be embedded in RootBlockHeader and hashed byte-identically to
// pyquarkchain's TokenBalanceMap.
type TokenBalances struct {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TokenBalances depends on the pending PR from Alan. Please sync/rebase this implementation onto the latest TokenBalances code after that PR lands, to avoid maintaining a duplicate or divergent type.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbfca80

@syntrust
syntrust requested a review from qzhodl July 23, 2026 08:35
Comment thread cmd/slave/main.go Outdated
}
nodeIDFlag = &cli.StringFlag{
Name: "node_id",
Usage: "Slave identity (e.g. S0) selecting which shards this process owns",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the "Usage" section mention that this node_id needs to match the name of the xxx field in the configuration?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in a31e269


Both: 8 chains (one shard each), 4 slaves `S0..S3` each owning 2 shards,
`FULL_SHARD_ID_LIST` form (S0's first id is written `0x1`), genesis `ALLOC` present.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add some notes regarding the configuration? For instance:
To expose the service to public, you need to change, "JSON_RPC_HOST" to 0.0.0.0,
as well as the following settings:
PRIVATE_JSON_RPC_HOST
ENABLE_TRANSACTION_HISTORY

Or add configuration files for specific purposes, such as a node with an index.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not related to this PR. We may expand/update this doc later.

Comment thread qkc/types/rootblock.go
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/qkc/account"
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is included in this minimal version rootblock to ensure the PR is self-contained; since more content will need to be added later, it would be best to include a TODO comment explaining this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in a31e269

Comment thread qkc/genesis/genesis.go Outdated
// mixhash, and signature are all empty/zero, exactly as the Python default header.
// The resulting header.Hash() is byte-identical to pyquarkchain's
// create_root_block().header.get_hash().
func RootBlock(qkc *config.QuarkChainConfig) (*types.RootBlockHeader, error) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RootBlock -> CreateRootBlock ?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in a31e269

Comment thread qkc/genesis.go
@@ -0,0 +1,79 @@
// Copyright 2026-2027, QuarkChain.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we moving it here?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you referring to?

@ping-ke ping-ke Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its previous path is core/genesis.go, should we put it qkc/core/genesis.go?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 38d5c80

Comment thread qkc/genesis.go
@@ -0,0 +1,79 @@
// Copyright 2026-2027, QuarkChain.

@ping-ke ping-ke Jul 28, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its previous path is core/genesis.go, should we put it qkc/core/genesis.go?

@syntrust
syntrust merged commit 7ca760f into goshard/base Jul 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants