Skip to content

feat(types): add QuarkChain MNT account and token types#24

Open
ping-ke wants to merge 3 commits into
goshard/basefrom
feature/mnt-core-types
Open

feat(types): add QuarkChain MNT account and token types#24
ping-ke wants to merge 3 commits into
goshard/basefrom
feature/mnt-core-types

Conversation

@ping-ke

@ping-ke ping-ke commented Jul 3, 2026

Copy link
Copy Markdown

Summary

  • Add MNT (Multi-Native Token) support to core/types, including a QKC 6-element RLP-encoded StateAccount and a TokenBalances type
  • Update genesis hash constants in params/config.go to match the new state root produced by QKC 6-element encoding
  • Remove the codegen file gen_account_rlp.go and replace it with hand-written EncodeRLP/DecodeRLP to support the QKC custom 6-field RLP format

Background

The standard Ethereum StateAccount uses 4-element RLP (Nonce, Balance, Root, CodeHash). The QuarkChain protocol extends this with two additional fields:

  • FullShardKey uint32: the shard key of the account
  • MntBalances TokenBalances: a map of non-default native token balances held by the account

This change produces a different state root from standard go-ethereum, requiring the genesis hash constants to be updated accordingly.

Changed Files

File Description
core/types/gen_account_rlp.go Deleted (replaced by hand-written EncodeRLP)
core/types/state_account.go Add FullShardKey and MntBalances fields
core/types/state_account_qkc.go QKC 6-element RLP encode/decode implementation
core/types/state_account_qkc_test.go Roundtrip tests + pyquarkchain compatibility tests
core/types/token.go TokenBalances type, DefaultTokenID = 35760 (= TokenIDEncode("QKC"))
core/types/token_test.go TokenBalances unit tests
core/types/uint32_rlp.go uint32 RLP helpers for token ID encoding/decoding
core/types/uint32_rlp_test.go uint32 RLP unit tests
params/config.go Update genesis hash constants to match QKC encoding

Key Design Decisions

DefaultTokenID = 35760: Equal to TokenIDEncode("QKC"), consistent with pyquarkchain. The QKC token balance is stored in the standard Balance field, not in the MntBalances map, to preserve EIP-20 compatibility.

Slim-RLP vs QKC format: The snapshot layer continues to use slim-RLP (4 fields, compatible with go-ethereum snapshots). The trie stores the QKC 6-element format. database_mpt.go handles re-encoding for the pathdb path.

Test Plan

  • go test ./core/types — all pass, including pyquarkchain compatibility vector tests
  • go build ./... — build successful

- Add TokenBalances type with sorted list encoding compatible with pyquarkchain
- Add StateAccount.MntBalances field and QKC 6-element RLP codec
  (replaces generated gen_account_rlp.go with hand-written EncodeRLP/DecodeRLP)
- Add uint32 RLP encoding helpers for token IDs
- Update genesis hashes to reflect QKC 6-element account encoding
- Add comprehensive tests: roundtrip, pyquarkchain encode/decode compatibility
Comment thread core/types/state_account.go Outdated
Comment thread core/types/state_account.go Outdated
Comment thread core/types/gen_account_rlp.go
@qzhodl

qzhodl commented Jul 8, 2026

Copy link
Copy Markdown

General note: the three inline issues above were all found in a first-pass Codex 5.5 Extra High review with no additional prompt engineering beyond asking it to review this PR. Before requesting review next time, please run a self-review pass with Codex 5.5 Extra High (or an equivalent high-reasoning review mode) and address the obvious state/snapshot/generation issues it finds first.

Comment 1: SlimAccount only held {Nonce,Balance,Root,CodeHash}, so the
slim-RLP path used by SlimAccountRLP (stateupdate.go account updates/
origins), FullAccount (pathdb rollback in triedb/pathdb/execute.go) and
flatReader.Account (snapshot flat read) silently dropped MntBalances and
FullShardKey. A QKC account served from any of those paths came back with
MntBalances=nil / FullShardKey=0 and re-committed a corrupted account,
forking the trie root.

Extend SlimAccount with:
  - MntBal       []byte (rlp optional) = TokenBalances.SerializeToBytes()
  - FullShardKey uint32 (rlp optional)

MntBal uses the []byte serialization (TokenBalances holds an unexported
map, not RLP-struct-encodable) and preserves the nil-vs-empty distinction
so the 0x80 / 0x8200c0 trie encoding stays byte-stable across the slim
round-trip. Unlike the trie qkcAccountRLP.TokenBal, the QKC default
balance is NOT merged into MntBal — slim keeps it in the Balance field.
Both fields are rlp optional so pre-MNT snapshots still decode. Because
FullAccount now reconstructs both fields, the pathdb rollback path is
covered without further changes.

Extend TestSlimRLPRoundTripEquivalence with fullShardKey / MNT-only /
MNT+QKC+shard cases (direct-QKC-encode == via-slim-encode).

Comment 3: remove the rlpgen go:generate directive. StateAccount now uses
the hand-written QKC codec (EncodeRLP/DecodeRLP in state_account_qkc.go);
regenerating gen_account_rlp.go would reintroduce a conflicting standard
4-field codec that drops MntBalances / FullShardKey. Replaced the
directive with a NOTE explaining why it must stay removed.

Comment 2 (empty() must consider MntBalances) is resolved downstream on
feature/mnt-state (stateObject.empty() checks IsBlankMnt(), covered by
TestEmptyAccountWithMntNotPruned); core/state is not part of this branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comment thread params/config.go Outdated
@ping-ke
ping-ke force-pushed the feature/mnt-core-types branch from 3860cb7 to 53e97c4 Compare July 16, 2026 12:08
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.

3 participants