allow adding Altair test blocks (#2872)

testblockutil currently fails to add test blocks to Altair state because
it assumes phase0 blocks in various places. This patch corrects this
limitation by using forked types internally. Note that existing clients
so far solely operate on phase0 blocks and should eventually be updated.
This commit is contained in:
Etan Kissling 2021-09-17 12:55:04 +02:00 committed by GitHub
parent aaf1ccde14
commit ddbbbae3c8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 92 additions and 73 deletions

View File

@ -97,7 +97,7 @@ cli do(slots = SLOTS_PER_EPOCH * 5,
withTimer(timers[t]):
signedBlock = addTestBlock(
state[], latest_block_root, cache, attestations = blockAttestations,
flags = flags)
flags = flags).phase0Block
latest_block_root = withTimerRet(timers[tHashBlock]):
hash_tree_root(signedBlock.message)
signedBlock.root = latest_block_root

View File

@ -113,7 +113,7 @@ suite "Attestation pool processing" & preset():
let
root1 = addTestBlock(
state.data, state.blck.root,
cache, attestations = attestations, nextSlot = false).root
cache, attestations = attestations, nextSlot = false).phase0Block.root
bc1 = get_beacon_committee(
state[].data, getStateField(state.data, slot), 0.CommitteeIndex, cache)
att1 = makeAttestation(state[].data, root1, bc1[0], cache)
@ -377,7 +377,7 @@ suite "Attestation pool processing" & preset():
test "Fork choice returns latest block with no attestations":
var cache = StateCache()
let
b1 = addTestBlock(state.data, dag.tail.root, cache)
b1 = addTestBlock(state.data, dag.tail.root, cache).phase0Block
b1Add = dag.addRawBlock(quarantine, b1) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -390,7 +390,7 @@ suite "Attestation pool processing" & preset():
head == b1Add[]
let
b2 = addTestBlock(state.data, b1.root, cache)
b2 = addTestBlock(state.data, b1.root, cache).phase0Block
b2Add = dag.addRawBlock(quarantine, b2) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -405,7 +405,7 @@ suite "Attestation pool processing" & preset():
test "Fork choice returns block with attestation":
var cache = StateCache()
let
b10 = makeTestBlock(state.data, dag.tail.root, cache)
b10 = makeTestBlock(state.data, dag.tail.root, cache).phase0Block
b10Add = dag.addRawBlock(quarantine, b10) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -420,7 +420,7 @@ suite "Attestation pool processing" & preset():
let
b11 = makeTestBlock(state.data, dag.tail.root, cache,
graffiti = GraffitiBytes [1'u8, 0, 0, 0 ,0 ,0 ,0 ,0 ,0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
)
).phase0Block
b11Add = dag.addRawBlock(quarantine, b11) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -466,7 +466,7 @@ suite "Attestation pool processing" & preset():
test "Trying to add a block twice tags the second as an error":
var cache = StateCache()
let
b10 = makeTestBlock(state.data, dag.tail.root, cache)
b10 = makeTestBlock(state.data, dag.tail.root, cache).phase0Block
b10Add = dag.addRawBlock(quarantine, b10) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -495,7 +495,7 @@ suite "Attestation pool processing" & preset():
dag.updateFlags.incl {skipBLSValidation}
var cache = StateCache()
let
b10 = addTestBlock(state.data, dag.tail.root, cache)
b10 = addTestBlock(state.data, dag.tail.root, cache).phase0Block
b10Add = dag.addRawBlock(quarantine, b10) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
@ -521,7 +521,7 @@ suite "Attestation pool processing" & preset():
get_committee_count_per_slot(state[].data, Epoch epoch, cache)
for slot in start_slot ..< start_slot + SLOTS_PER_EPOCH:
let new_block = addTestBlock(
state.data, block_root, cache, attestations = attestations)
state.data, block_root, cache, attestations = attestations).phase0Block
block_root = new_block.root
let blockRef = dag.addRawBlock(quarantine, new_block) do (

View File

@ -127,8 +127,8 @@ suite "Block pool processing" & preset():
cache = StateCache()
rewards = RewardInfo()
att0 = makeFullAttestations(state[], dag.tail.root, 0.Slot, cache)
b1 = addTestBlock(state[], dag.tail.root, cache, attestations = att0)
b2 = addTestBlock(state[], b1.root, cache)
b1 = addTestBlock(state[], dag.tail.root, cache, attestations = att0).phase0Block
b2 = addTestBlock(state[], b1.root, cache).phase0Block
test "getRef returns nil for missing blocks":
check:
dag.getRef(default Eth2Digest) == nil
@ -181,7 +181,7 @@ suite "Block pool processing" & preset():
rewards, {})
let
b4 = addTestBlock(state[], b2.root, cache)
b4 = addTestBlock(state[], b2.root, cache).phase0Block
b4Add = dag.addRawBlock(quarantine, b4, nilPhase0Callback)
check:
@ -357,7 +357,7 @@ suite "chain DAG finalization tests" & preset():
test "prune heads on finalization" & preset():
# Create a fork that will not be taken
var
blck = makeTestBlock(dag.headState.data, dag.head.root, cache)
blck = makeTestBlock(dag.headState.data, dag.head.root, cache).phase0Block
tmpState = assignClone(dag.headState.data)
check:
process_slots(
@ -365,7 +365,7 @@ suite "chain DAG finalization tests" & preset():
getStateField(tmpState[], slot) + (5 * SLOTS_PER_EPOCH).uint64,
cache, rewards, {})
let lateBlock = addTestBlock(tmpState[], dag.head.root, cache)
let lateBlock = addTestBlock(tmpState[], dag.head.root, cache).phase0Block
block:
let status = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
check: status.isOk()
@ -381,7 +381,7 @@ suite "chain DAG finalization tests" & preset():
blck = addTestBlock(
tmpState[], dag.head.root, cache,
attestations = makeFullAttestations(
tmpState[], dag.head.root, getStateField(tmpState[], slot), cache, {}))
tmpState[], dag.head.root, getStateField(tmpState[], slot), cache, {})).phase0Block
let added = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
check: added.isOk()
dag.updateHead(added[], quarantine)
@ -452,7 +452,7 @@ suite "chain DAG finalization tests" & preset():
if i == SLOTS_PER_EPOCH - 1:
assign(prestate[], dag.headState.data)
let blck = makeTestBlock(dag.headState.data, dag.head.root, cache)
let blck = makeTestBlock(dag.headState.data, dag.head.root, cache).phase0Block
let added = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
check: added.isOk()
dag.updateHead(added[], quarantine)
@ -469,7 +469,7 @@ suite "chain DAG finalization tests" & preset():
cache, rewards, {})
# create another block, orphaning the head
let blck = makeTestBlock(prestate[], dag.head.parent.root, cache)
let blck = makeTestBlock(prestate[], dag.head.parent.root, cache).phase0Block
# Add block, but don't update head
let added = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
@ -486,7 +486,7 @@ suite "chain DAG finalization tests" & preset():
for blck in makeTestBlocks(
dag.headState.data, dag.head.root, cache, int(SLOTS_PER_EPOCH * 6 - 2),
true):
let added = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
let added = dag.addRawBlock(quarantine, blck.phase0Block, nilPhase0Callback)
check: added.isOk()
dag.updateHead(added[], quarantine)
dag.pruneAtFinalization()
@ -501,7 +501,7 @@ suite "chain DAG finalization tests" & preset():
dag.headState.data, dag.head.root, cache,
attestations = makeFullAttestations(
dag.headState.data, dag.head.root, getStateField(dag.headState.data, slot),
cache, {}))
cache, {})).phase0Block
let added = dag.addRawBlock(quarantine, blck, nilPhase0Callback)
check: added.isOk()
@ -563,7 +563,7 @@ suite "Old database versions" & preset():
state = newClone(dag.headState.data)
cache = StateCache()
att0 = makeFullAttestations(state[], dag.tail.root, 0.Slot, cache)
b1 = addTestBlock(state[], dag.tail.root, cache, attestations = att0)
b1 = addTestBlock(state[], dag.tail.root, cache, attestations = att0).phase0Block
b1Add = dag.addRawBlock(quarantine, b1, nilPhase0Callback)
check:
@ -600,7 +600,7 @@ suite "Diverging hardforks":
# Because the first block is after the Altair transition, the only block in
# common is the tail block
var
b1 = addTestBlock(tmpState[], dag.tail.root, cache)
b1 = addTestBlock(tmpState[], dag.tail.root, cache).phase0Block
b1Add = dag.addRawBlock(quarantine, b1, nilPhase0Callback)
check b1Add.isOk()
@ -618,7 +618,7 @@ suite "Diverging hardforks":
# There's a block in the shared-correct phase0 hardfork, before epoch 2
var
b1 = addTestBlock(tmpState[], dag.tail.root, cache)
b1 = addTestBlock(tmpState[], dag.tail.root, cache).phase0Block
b1Add = dag.addRawBlock(quarantine, b1, nilPhase0Callback)
check:
@ -629,7 +629,7 @@ suite "Diverging hardforks":
cache, rewards, {})
var
b2 = addTestBlock(tmpState[], b1.root, cache)
b2 = addTestBlock(tmpState[], b1.root, cache).phase0Block
b2Add = dag.addRawBlock(quarantine, b2, nilPhase0Callback)
check b2Add.isOk()

View File

@ -74,7 +74,7 @@ suite "Gossip validation " & preset():
for blck in makeTestBlocks(
dag.headState.data, dag.head.root, cache,
int(SLOTS_PER_EPOCH * 5), false):
let added = dag.addRawBlock(quarantine, blck) do (
let added = dag.addRawBlock(quarantine, blck.phase0Block) do (
blckRef: BlockRef, signedBlock: phase0.TrustedSignedBeaconBlock,
epochRef: EpochRef):
# Callback add to fork choice if valid

View File

@ -10,7 +10,7 @@ import
options, stew/endians2,
../beacon_chain/[beacon_node_types],
../beacon_chain/validators/validator_pool,
../beacon_chain/spec/datatypes/[phase0, altair, merge],
../beacon_chain/spec/datatypes/merge,
../beacon_chain/spec/[helpers, signatures, state_transition, forks],
../beacon_chain/consensus_object_pools/attestation_pool
@ -60,19 +60,18 @@ func makeInitialDeposits*(
result.add makeDeposit(i, flags)
func signBlock(
fork: Fork, genesis_validators_root: Eth2Digest, blck: phase0.BeaconBlock,
privKey: ValidatorPrivKey, flags: UpdateFlags = {}): phase0.SignedBeaconBlock =
let root = hash_tree_root(blck)
phase0.SignedBeaconBlock(
message: blck,
root: root,
signature:
fork: Fork, genesis_validators_root: Eth2Digest, forked: ForkedBeaconBlock,
privKey: ValidatorPrivKey, flags: UpdateFlags = {}): ForkedSignedBeaconBlock =
let
slot = withBlck(forked): blck.slot
root = hash_tree_root(forked)
signature =
if skipBlsValidation notin flags:
get_block_signature(
fork, genesis_validators_root, blck.slot, root, privKey).toValidatorSig()
fork, genesis_validators_root, slot, root, privKey).toValidatorSig()
else:
ValidatorSig()
)
ForkedSignedBeaconBlock.init(forked, root, signature)
proc addTestBlock*(
state: var ForkedHashedBeaconState,
@ -83,7 +82,7 @@ proc addTestBlock*(
deposits = newSeq[Deposit](),
graffiti = default(GraffitiBytes),
flags: set[UpdateFlag] = {},
nextSlot = true): phase0.SignedBeaconBlock =
nextSlot = true): ForkedSignedBeaconBlock =
# Create and add a block to state - state will advance by one slot!
if nextSlot:
var rewards: RewardInfo
@ -104,34 +103,61 @@ proc addTestBlock*(
else:
ValidatorSig()
let
message = makeBeaconBlock(
defaultRuntimeConfig,
state.hbsPhase0,
proposer_index.get(),
parent_root,
randao_reveal,
# Keep deposit counts internally consistent.
Eth1Data(
deposit_root: eth1_data.deposit_root,
deposit_count: getStateField(state, eth1_deposit_index) + deposits.lenu64,
block_hash: eth1_data.block_hash),
graffiti,
attestations,
deposits,
@[],
@[],
@[],
default(ExecutionPayload),
noRollback,
cache)
doAssert message.isOk(), "Should have created a valid block!"
let message =
case state.beaconStateFork
of forkPhase0:
let res = makeBeaconBlock(
defaultRuntimeConfig,
state.hbsPhase0,
proposer_index.get(),
parent_root,
randao_reveal,
# Keep deposit counts internally consistent.
Eth1Data(
deposit_root: eth1_data.deposit_root,
deposit_count: getStateField(state, eth1_deposit_index) + deposits.lenu64,
block_hash: eth1_data.block_hash),
graffiti,
attestations,
deposits,
@[],
@[],
@[],
default(ExecutionPayload),
noRollback,
cache)
doAssert res.isOk(), "Should have created a valid block!"
ForkedBeaconBlock.init(res.get())
of forkAltair:
let res = makeBeaconBlock(
defaultRuntimeConfig,
state.hbsAltair,
proposer_index.get(),
parent_root,
randao_reveal,
# Keep deposit counts internally consistent.
Eth1Data(
deposit_root: eth1_data.deposit_root,
deposit_count: getStateField(state, eth1_deposit_index) + deposits.lenu64,
block_hash: eth1_data.block_hash),
graffiti,
attestations,
deposits,
@[],
@[],
@[],
SyncAggregate(
sync_committee_signature: ValidatorSig.infinity),
default(ExecutionPayload),
noRollback,
cache)
doAssert res.isOk(), "Should have created a valid block!"
ForkedBeaconBlock.init(res.get())
let
new_block = signBlock(
getStateField(state, fork),
getStateField(state, genesis_validators_root), message.get(), privKey,
getStateField(state, genesis_validators_root), message, privKey,
flags)
new_block
@ -143,7 +169,7 @@ proc makeTestBlock*(
eth1_data = Eth1Data(),
attestations = newSeq[Attestation](),
deposits = newSeq[Deposit](),
graffiti = default(GraffitiBytes)): phase0.SignedBeaconBlock =
graffiti = default(GraffitiBytes)): ForkedSignedBeaconBlock =
# Create a block for `state.slot + 1` - like a block proposer would do!
# It's a bit awkward - in order to produce a block for N+1, we need to
# calculate what the state will look like after that block has been applied,
@ -284,33 +310,26 @@ func makeFullAttestations*(
attestation.signature = agg.finish().toValidatorSig()
result.add attestation
iterator makeTestBlocks(
state: phase0.HashedBeaconState,
iterator makeTestBlocks*(
state: ForkedHashedBeaconState,
parent_root: Eth2Digest,
cache: var StateCache,
blocks: int,
attested: bool): phase0.SignedBeaconBlock =
attested: bool): ForkedSignedBeaconBlock =
var
# TODO replace wrapper with more native usage
state = (ref ForkedHashedBeaconState)(
hbsPhase0: state, beaconStateFork: forkPhase0)
state = assignClone(state)[]
parent_root = parent_root
for _ in 0..<blocks:
let attestations = if attested:
makeFullAttestations(state[], parent_root, getStateField(state[], slot), cache)
makeFullAttestations(state, parent_root, getStateField(state, slot), cache)
else:
@[]
let blck = addTestBlock(
state[], parent_root, cache, attestations = attestations)
state, parent_root, cache, attestations = attestations)
yield blck
parent_root = blck.root
iterator makeTestBlocks*(state: ForkedHashedBeaconState; parent_root: Eth2Digest;
cache: var StateCache; blocks: int; attested: bool): phase0.SignedBeaconBlock =
for blck in makeTestBlocks(state.hbsPhase0, parent_root, cache, blocks, attested):
yield blck
proc getAttestationsForTestBlock*(
pool: var AttestationPool, stateData: StateData, cache: var StateCache):
seq[Attestation] =