Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion quarkchain/cluster/posw.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ def get_posw_info(
header: Header,
stake_func: Callable[[], int],
block_cnt: Dict[bytes, int],
stake_per_block: Optional[int] = None,
signer: Optional[bytes] = None,
) -> Optional[PoSWInfo]:
if (
Expand All @@ -75,7 +76,9 @@ def get_posw_info(
# evaluate stakes before the to-be-added block
stakes = stake_func()
coinbase_recipient = header.coinbase_address.recipient
block_threshold = min(config.WINDOW_SIZE, stakes // config.TOTAL_STAKE_PER_BLOCK)

required_stakes_per_block = stake_per_block or config.TOTAL_STAKE_PER_BLOCK
block_threshold = min(config.WINDOW_SIZE, stakes // required_stakes_per_block)
cnt = block_cnt.get(coinbase_recipient, 0)

diff = header.difficulty
Expand Down
4 changes: 3 additions & 1 deletion quarkchain/cluster/root_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -665,4 +665,6 @@ def get_posw_info(
block.header.hash_prev_block,
self.db.get_root_block_header_by_hash,
)
return get_posw_info(config, block.header, lambda: stakes, block_cnt, signer)
return get_posw_info(
config, block.header, lambda: stakes, block_cnt, signer=signer
)
35 changes: 22 additions & 13 deletions quarkchain/cluster/shard_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -1024,22 +1024,13 @@ def add_block(
return evm_state.xshard_list, coinbase_amount_map

def get_coinbase_amount_map(self, height) -> TokenBalanceMap:
epoch = (
height
// self.env.quark_chain_config.shards[self.full_shard_id].EPOCH_INTERVAL
)
decay_numerator = (
self.env.quark_chain_config.block_reward_decay_factor.numerator ** epoch
)
decay_denominator = (
self.env.quark_chain_config.block_reward_decay_factor.denominator ** epoch
)
coinbase_amount = (
self.env.quark_chain_config.shards[self.full_shard_id].COINBASE_AMOUNT
self.__decay_by_epoch(
self.env.quark_chain_config.shards[self.full_shard_id].COINBASE_AMOUNT,
height,
)
* self.local_fee_rate.numerator
* decay_numerator
// self.local_fee_rate.denominator
// decay_denominator
)
# shard coinbase only in genesis_token
return TokenBalanceMap(
Expand Down Expand Up @@ -1838,6 +1829,10 @@ def _posw_info(self, block: MinorBlock) -> Optional[PoSWInfo]:
if header.height == 0: # genesis
return None
block_cnt = self._get_posw_coinbase_blockcnt(header.hash_prev_minor_block)
# require stakes will decay as our mining rewards
stake_per_block = self.__decay_by_epoch(
self.shard_config.POSW_CONFIG.TOTAL_STAKE_PER_BLOCK, header.height
)
return get_posw_info(
self.shard_config.POSW_CONFIG,
header,
Expand All @@ -1848,6 +1843,7 @@ def _posw_info(self, block: MinorBlock) -> Optional[PoSWInfo]:
self.env.quark_chain_config.genesis_token,
),
block_cnt,
stake_per_block=stake_per_block,
)

def _get_evm_state_from_height(self, height: Optional[int]) -> Optional[EvmState]:
Expand Down Expand Up @@ -1970,3 +1966,16 @@ def _qkchashx_enabled(self, header):
config.ENABLE_QKCHASHX_HEIGHT is not None
and header.height >= config.ENABLE_QKCHASHX_HEIGHT
)

def __decay_by_epoch(self, value: int, block_height: int):
epoch = (
block_height
// self.env.quark_chain_config.shards[self.full_shard_id].EPOCH_INTERVAL
)
decay_numerator = (
self.env.quark_chain_config.block_reward_decay_factor.numerator ** epoch
)
decay_denominator = (
self.env.quark_chain_config.block_reward_decay_factor.denominator ** epoch
)
return value * decay_numerator // decay_denominator
27 changes: 20 additions & 7 deletions quarkchain/cluster/tests/test_shard_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -1532,9 +1532,6 @@ def test_xshard_gas_limit_from_multiple_shards(self):
env1 = get_test_env(
genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64
)
env2 = get_test_env(
genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64
)
state0 = create_default_shard_state(env=env0, shard_id=0)
state1 = create_default_shard_state(env=env1, shard_id=16)
state2 = create_default_shard_state(env=env1, shard_id=8)
Expand Down Expand Up @@ -1679,10 +1676,9 @@ def test_xshard_gas_limit_from_multiple_shards(self):
10000000 + 1000000 + 12345 + 888888 + 111111,
)

def test_xshard_rootblock_coinbase(self):
def test_xshard_root_block_coinbase(self):
id1 = Identity.create_random_identity()
acc1 = Address.create_from_identity(id1, full_shard_key=0)
acc2 = Address.create_from_identity(id1, full_shard_key=16)

env0 = get_test_env(
genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64
Expand Down Expand Up @@ -1738,7 +1734,6 @@ def test_xshard_sender_gas_limit(self):
id1 = Identity.create_random_identity()
acc1 = Address.create_from_identity(id1, full_shard_key=0)
acc2 = Address.create_from_identity(id1, full_shard_key=16)
acc3 = Address.create_random_account(full_shard_key=0)

env0 = get_test_env(
genesis_account=acc1, genesis_minor_quarkash=10000000, shard_size=64
Expand Down Expand Up @@ -2775,7 +2770,6 @@ def test_enable_tx_timestamp(self):
def test_enable_evm_timestamp_with_contract_create(self):
id1 = Identity.create_random_identity()
acc1 = Address.create_from_identity(id1, full_shard_key=0)
acc2 = Address.create_random_account(full_shard_key=0)

env = get_test_env(genesis_account=acc1, genesis_minor_quarkash=10000000)
state = create_default_shard_state(env=env)
Expand Down Expand Up @@ -3727,3 +3721,22 @@ def tx_gen(to):
state_to.get_token_balance(miner.recipient, token_id=self.genesis_token),
self.get_after_tax_reward(self.shard_coinbase + (3 * gas_price) * 9000),
)

def test_posw_stake_by_block_decay_by_epoch(self):
acc = Address(b"\x01" * 20, full_shard_key=0)
env = get_test_env(genesis_account=acc, genesis_minor_quarkash=200)
state = create_default_shard_state(env=env, shard_id=0, posw_override=True)

state.shard_config.CONSENSUS_TYPE = ConsensusType.POW_DOUBLESHA256
state.shard_config.POSW_CONFIG.TOTAL_STAKE_PER_BLOCK = 100
state.shard_config.POSW_CONFIG.WINDOW_SIZE = 256

b1 = state.get_tip().create_block_to_append(address=acc)
posw_info = state._posw_info(b1)
# 200 qkc with 100 required per block, should equal 2 mineable blocks
self.assertEqual(posw_info.posw_mineable_blocks, 200 / 100)

# decay (factor = 0.5) should kick in and double mineable blocks
b1.header.height = state.shard_config.EPOCH_INTERVAL
posw_info = state._posw_info(b1)
self.assertEqual(posw_info.posw_mineable_blocks, 200 / (100 / 2))