Blockchain timestamps fix (#2302)

* incomplete push for debugging

* block timestamp in mempool

* rename

* farm tx block

Co-authored-by: matt <matt@chia.net>
This commit is contained in:
Yostra 2021-04-21 19:43:02 -04:00 committed by GitHub
parent 572110b7df
commit 328e4cd276
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 31 additions and 25 deletions

View File

@ -71,38 +71,36 @@ def mempool_assert_relative_block_height_exceeds(
return None
def mempool_assert_absolute_time_exceeds(
condition: ConditionWithArgs, timestamp: Optional[uint64] = None
) -> Optional[Err]:
def mempool_assert_absolute_time_exceeds(condition: ConditionWithArgs, timestamp: uint64) -> Optional[Err]:
"""
Check if the current time in millis exceeds the time specified by condition
Check if the current time in seconds exceeds the time specified by condition
"""
try:
expected_mili_time = int_from_bytes(condition.vars[0])
expected_seconds = int_from_bytes(condition.vars[0])
except ValueError:
return Err.INVALID_CONDITION
if timestamp is None:
timestamp = uint64(int(time.time() * 1000))
if timestamp < expected_mili_time:
timestamp = uint64(int(time.time()))
if timestamp < expected_seconds:
return Err.ASSERT_SECONDS_ABSOLUTE_FAILED
return None
def mempool_assert_relative_time_exceeds(
condition: ConditionWithArgs, unspent: CoinRecord, timestamp: Optional[uint64] = None
condition: ConditionWithArgs, unspent: CoinRecord, timestamp: uint64
) -> Optional[Err]:
"""
Check if the current time in millis exceeds the time specified by condition
Check if the current time in seconds exceeds the time specified by condition
"""
try:
expected_mili_time = int_from_bytes(condition.vars[0])
expected_seconds = int_from_bytes(condition.vars[0])
except ValueError:
return Err.INVALID_CONDITION
if timestamp is None:
timestamp = uint64(int(time.time() * 1000))
if timestamp < expected_mili_time + unspent.timestamp:
timestamp = uint64(int(time.time()))
if timestamp < expected_seconds + unspent.timestamp:
return Err.ASSERT_SECONDS_RELATIVE_FAILED
return None
@ -196,7 +194,7 @@ def mempool_check_conditions_dict(
puzzle_announcement_names: Set[bytes32],
conditions_dict: Dict[ConditionOpcode, List[ConditionWithArgs]],
prev_transaction_block_height: uint32,
timestamp: Optional[uint64] = None,
timestamp: uint64,
) -> Optional[Err]:
"""
Check all conditions against current state.

View File

@ -274,13 +274,14 @@ class MempoolManager:
elif name in additions_dict:
removal_coin = additions_dict[name]
# TODO(straya): what timestamp to use here?
assert self.peak.timestamp is not None
removal_record = CoinRecord(
removal_coin,
uint32(self.peak.height + 1), # In mempool, so will be included in next height
uint32(0),
False,
False,
uint64(int(time.time())),
uint64(self.peak.timestamp + 1),
)
assert removal_record is not None
@ -367,12 +368,14 @@ class MempoolManager:
chialisp_height = (
self.peak.prev_transaction_block_height if not self.peak.is_transaction_block else self.peak.height
)
assert self.peak.timestamp is not None
error = mempool_check_conditions_dict(
coin_record,
coin_announcements_in_spend,
puzzle_announcements_in_spend,
npc.condition_dict,
uint32(chialisp_height),
self.peak.timestamp,
)
if error:
@ -465,9 +468,12 @@ class MempoolManager:
"""
if new_peak is None:
return []
if new_peak.is_transaction_block is False:
return []
if self.peak == new_peak:
return []
if int(time.time()) <= self.constants.INITIAL_FREEZE_END_TIMESTAMP:
assert new_peak.timestamp is not None
if new_peak.timestamp <= self.constants.INITIAL_FREEZE_END_TIMESTAMP:
return []
self.peak = new_peak

View File

@ -7,6 +7,7 @@ import pytest
from chia.full_node.mempool import Mempool
from chia.protocols import full_node_protocol
from chia.simulator.simulator_protocol import FarmNewBlockProtocol
from chia.types.announcement import Announcement
from chia.types.blockchain_format.coin import Coin
from chia.types.coin_solution import CoinSolution
@ -458,7 +459,7 @@ class TestMempoolManager:
await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3)
time_now = uint64(int(time() * 1000))
time_now = uint64(int(time()))
cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, [time_now.to_bytes(8, "big")])
dic = {cvp.opcode: [cvp]}
@ -474,7 +475,7 @@ class TestMempoolManager:
assert sb1 is spend_bundle1
@pytest.mark.asyncio
async def test_assert_time_exceeds_both_cases(self, two_nodes):
async def test_assert_time_relative_exceeds(self, two_nodes):
reward_ph = WALLET_A.get_new_puzzlehash()
full_node_1, full_node_2, server_1, server_2 = two_nodes
blocks = await full_node_1.get_all_full_blocks()
@ -493,20 +494,22 @@ class TestMempoolManager:
await time_out_assert(60, node_height_at_least, True, full_node_1, start_height + 3)
time_now = uint64(int(time() * 1000))
time_now_plus_3 = time_now + 3000
time_relative = uint64(3)
cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_ABSOLUTE, [time_now_plus_3.to_bytes(8, "big")])
cvp = ConditionWithArgs(ConditionOpcode.ASSERT_SECONDS_RELATIVE, [time_relative.to_bytes(8, "big")])
dic = {cvp.opcode: [cvp]}
spend_bundle1 = generate_test_spend_bundle(list(blocks[-1].get_included_reward_coins())[0], dic)
assert spend_bundle1 is not None
tx1: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle1)
await full_node_1.respond_transaction(tx1, peer)
# Sleep so that 3 sec passes
await asyncio.sleep(3)
sb1 = full_node_1.full_node.mempool_manager.get_spendbundle(spend_bundle1.name())
assert sb1 is None
for i in range(0, 4):
await full_node_1.farm_new_transaction_block(FarmNewBlockProtocol(32 * b"0"))
tx2: full_node_protocol.RespondTransaction = full_node_protocol.RespondTransaction(spend_bundle1)
await full_node_1.respond_transaction(tx2, peer)

View File

@ -118,8 +118,7 @@ class TestWalletRpc:
assert (await client.get_wallet_balance("1"))["confirmed_wallet_balance"] == initial_funds
for i in range(0, 5):
await client.farm_block(encode_puzzle_hash(ph_2, "xch"))
await asyncio.sleep(0.5)
await full_node_api.farm_new_transaction_block(FarmNewBlockProtocol(ph_2))
async def eventual_balance():
return (await client.get_wallet_balance("1"))["confirmed_wallet_balance"]