add sub height

This commit is contained in:
Yostra 2021-01-07 23:49:15 -05:00 committed by Yostra
parent 4599093541
commit c0ba32b488
10 changed files with 166 additions and 93 deletions

View File

@ -106,7 +106,8 @@ class CCWallet:
raise ValueError("Internal Error, unable to generate new coloured coin")
regular_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=cc_coin.puzzle_hash,
amount=uint64(cc_coin.amount),
@ -122,7 +123,8 @@ class CCWallet:
type=uint32(TransactionType.OUTGOING_TX.value),
)
cc_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=cc_coin.puzzle_hash,
amount=uint64(cc_coin.amount),
@ -361,7 +363,8 @@ class CCWallet:
if send:
regular_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=cc_puzzle_hash,
amount=uint64(0),
@ -377,7 +380,8 @@ class CCWallet:
type=uint32(TransactionType.INCOMING_TX.value),
)
cc_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=cc_puzzle_hash,
amount=uint64(0),
@ -457,7 +461,7 @@ class CCWallet:
used_coins: Set = set()
# Use older coins first
spendable.sort(key=lambda r: r.confirmed_block_index)
spendable.sort(key=lambda r: r.confirmed_block_sub_height)
# Try to use coins from the store, if there isn't enough of "unused"
# coins use change coins that are not confirmed yet
@ -471,7 +475,7 @@ class CCWallet:
continue
sum += coinrecord.coin.amount
used_coins.add(coinrecord.coin)
self.log.info(f"Selected coin: {coinrecord.coin.name()} at height {coinrecord.confirmed_block_index}!")
self.log.info(f"Selected coin: {coinrecord.coin.name()} at height {coinrecord.confirmed_block_height}!")
# This happens when we couldn't use one of the coins because it's already used
# but unconfirmed, and we are waiting for the change. (unconfirmed_additions)
@ -572,7 +576,8 @@ class CCWallet:
)
# TODO add support for array in stored records
return TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=puzzle_hashes[0],
amount=uint64(outgoing_amount),

View File

@ -304,7 +304,8 @@ class RLWallet:
rl_coin = await self._get_rl_coin()
puzzle_hash = rl_coin.puzzle_hash if rl_coin is not None else None
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=puzzle_hash,
amount=uint64(0),
@ -326,12 +327,13 @@ class RLWallet:
self.rl_coin_record = await self._get_rl_coin_record()
if self.rl_coin_record is None:
return uint64(0)
# TODO get proper peak here
lca_header_hash = self.wallet_state_manager.lca
lca = self.wallet_state_manager.block_records[lca_header_hash]
height = lca.height
assert self.rl_info.limit is not None
unlocked = int(
((height - self.rl_coin_record.confirmed_block_index) / self.rl_info.interval) * int(self.rl_info.limit)
((height - self.rl_coin_record.confirmed_block_height) / self.rl_info.interval) * int(self.rl_info.limit)
)
total_amount = self.rl_coin_record.coin.amount
available_amount = min(unlocked, total_amount)
@ -515,7 +517,8 @@ class RLWallet:
spend_bundle = await self.rl_sign_transaction(transaction)
return TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=to_puzzle_hash,
amount=uint64(amount),
@ -596,7 +599,8 @@ class RLWallet:
spend_bundle = await self.clawback_rl_coin(to_puzzle_hash, fee)
return TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=to_puzzle_hash,
amount=uint64(0),

View File

@ -538,7 +538,8 @@ class TradeManager:
# debug_spend_bundle(spend_bundle)
if chia_discrepancy < 0:
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=now,
to_puzzle_hash=token_bytes(),
amount=uint64(abs(chia_discrepancy)),
@ -555,7 +556,8 @@ class TradeManager:
)
else:
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=token_bytes(),
amount=uint64(abs(chia_discrepancy)),
@ -576,7 +578,8 @@ class TradeManager:
wallet = wallets[colour]
if chia_discrepancy > 0:
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=token_bytes(),
amount=uint64(abs(amount)),
@ -593,7 +596,8 @@ class TradeManager:
)
else:
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=token_bytes(),
amount=uint64(abs(amount)),
@ -611,7 +615,8 @@ class TradeManager:
my_tx_records.append(tx_record)
tx_record = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=uint64(int(time.time())),
to_puzzle_hash=token_bytes(),
amount=uint64(0),

View File

@ -17,7 +17,8 @@ class TransactionRecord(Streamable):
Used for storing transaction data and status in wallets.
"""
confirmed_at_index: uint32
confirmed_at_sub_height: uint32
confirmed_at_height: uint32
created_at_time: uint64
to_puzzle_hash: bytes32
amount: uint64

View File

@ -174,7 +174,7 @@ class Wallet:
used_coins: Set = set()
# Use older coins first
unspent.sort(key=lambda r: r.confirmed_block_index)
unspent.sort(key=lambda r: r.confirmed_block_sub_height)
# Try to use coins from the store, if there isn't enough of "unused"
# coins use change coins that are not confirmed yet
@ -190,7 +190,7 @@ class Wallet:
continue
sum_value += coinrecord.coin.amount
used_coins.add(coinrecord.coin)
self.log.info(f"Selected coin: {coinrecord.coin.name()} at height {coinrecord.confirmed_block_index}!")
self.log.info(f"Selected coin: {coinrecord.coin.name()} at height {coinrecord.confirmed_block_height}!")
# This happens when we couldn't use one of the coins because it's already used
# but unconfirmed, and we are waiting for the change. (unconfirmed_additions)
@ -273,7 +273,8 @@ class Wallet:
rem_list: List[Coin] = list(spend_bundle.removals())
return TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=now,
to_puzzle_hash=puzzle_hash,
amount=uint64(amount),

View File

@ -237,12 +237,12 @@ class WalletBlockchain:
sub_block.header_hash
)
assert block is not None
self.sub_height_to_hash[uint32(0)] = block.header_hash
for removed in block.removals:
self.log.info(f"Removed: {removed.name()}")
await self.coins_of_interest_received(
block.removals, block.additions, block.height, block.sub_block_height
)
self.sub_height_to_hash[uint32(0)] = block.header_hash
self.peak_sub_height = uint32(0)
return uint32(0)
return None
@ -264,7 +264,7 @@ class WalletBlockchain:
else:
fork_hash = self.sub_height_to_hash[uint32(fork_h)]
fork_block = self.sub_blocks[fork_hash]
await self.reorg_rollback(fork_block.height)
await self.reorg_rollback(fork_block.sub_block_height)
# Rollback sub_epoch_summaries
heights_to_delete = []

View File

@ -16,8 +16,10 @@ class WalletCoinRecord(Streamable):
"""
coin: Coin
confirmed_block_index: uint32
spent_block_index: uint32
confirmed_block_sub_height: uint32
confirmed_block_height: uint32
spent_block_sub_height: uint32
spent_block_height: uint32
spent: bool
coinbase: bool
wallet_type: WalletType

View File

@ -27,8 +27,10 @@ class WalletCoinStore:
(
"CREATE TABLE IF NOT EXISTS coin_record("
"coin_name text PRIMARY KEY,"
" confirmed_index bigint,"
" spent_index bigint,"
" confirmed_sub_height bigint,"
" confirmed_height bigint,"
" spent_sub_height bigint,"
" spent_height bigint,"
" spent int,"
" coinbase int,"
" puzzle_hash text,"
@ -41,10 +43,15 @@ class WalletCoinStore:
# Useful for reorg lookups
await self.db_connection.execute(
"CREATE INDEX IF NOT EXISTS coin_confirmed_index on coin_record(confirmed_index)"
"CREATE INDEX IF NOT EXISTS coin_confirmed_sub_height on coin_record(confirmed_sub_height)"
)
await self.db_connection.execute("CREATE INDEX IF NOT EXISTS coin_spent_index on coin_record(spent_index)")
await self.db_connection.execute(
"CREATE INDEX IF NOT EXISTS coin_confirmed_height on coin_record(confirmed_height)"
)
await self.db_connection.execute(
"CREATE INDEX IF NOT EXISTS coin_spent_sub_height on coin_record(spent_sub_height)"
)
await self.db_connection.execute("CREATE INDEX IF NOT EXISTS coin_spent_height on coin_record(spent_height)")
await self.db_connection.execute("CREATE INDEX IF NOT EXISTS coin_spent on coin_record(spent)")
@ -66,11 +73,13 @@ class WalletCoinStore:
# Store CoinRecord in DB and ram cache
async def add_coin_record(self, record: WalletCoinRecord) -> None:
cursor = await self.db_connection.execute(
"INSERT OR REPLACE INTO coin_record VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT OR REPLACE INTO coin_record VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
record.coin.name().hex(),
record.confirmed_block_index,
record.spent_block_index,
record.confirmed_block_sub_height,
record.confirmed_block_height,
record.spent_block_sub_height,
record.spent_block_height,
int(record.spent),
int(record.coinbase),
str(record.coin.puzzle_hash.hex()),
@ -90,14 +99,16 @@ class WalletCoinStore:
del self.coin_record_cache[first_in]
# Update coin_record to be spent in DB
async def set_spent(self, coin_name: bytes32, index: uint32):
async def set_spent(self, coin_name: bytes32, sub_height: uint32, height: uint32):
current: Optional[WalletCoinRecord] = await self.get_coin_record(coin_name)
if current is None:
return
spent: WalletCoinRecord = WalletCoinRecord(
current.coin,
current.confirmed_block_index,
index,
current.confirmed_block_sub_height,
current.confirmed_block_height,
sub_height,
height,
True,
current.coinbase,
current.wallet_type,
@ -114,8 +125,8 @@ class WalletCoinStore:
row = await cursor.fetchone()
await cursor.close()
if row is not None:
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
return WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9])
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
return WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
return None
async def get_first_coin_height(self) -> Optional[uint32]:
@ -138,7 +149,7 @@ class WalletCoinStore:
coins = set()
if height is not None:
cursor = await self.db_connection.execute(
"SELECT * from coin_record WHERE (spent=? OR spent_index>?) AND confirmed_index<=?",
"SELECT * from coin_record WHERE (spent=? OR spent_height>?) AND confirmed_height<=?",
(0, height, height),
)
else:
@ -146,8 +157,10 @@ class WalletCoinStore:
rows = await cursor.fetchall()
await cursor.close()
for row in rows:
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coins.add(
WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
)
return coins
async def get_unspent_coins_for_wallet(self, wallet_id: int) -> Set[WalletCoinRecord]:
@ -161,8 +174,10 @@ class WalletCoinStore:
rows = await cursor.fetchall()
await cursor.close()
for row in rows:
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coins.add(
WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
)
return coins
async def get_all_coins(self) -> Set[WalletCoinRecord]:
@ -173,11 +188,13 @@ class WalletCoinStore:
rows = await cursor.fetchall()
await cursor.close()
for row in rows:
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coins.add(
WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
)
return coins
async def get_spendable_for_index(self, index: int, wallet_id: int) -> Set[WalletCoinRecord]:
async def get_spendable_for_index(self, height: int, wallet_id: int) -> Set[WalletCoinRecord]:
"""
Returns set of unspent coin records that are not coinbases, or if they are coinbases,
must have been confirmed at or before index.
@ -185,8 +202,8 @@ class WalletCoinStore:
coins = set()
cursor_coinbase_coins = await self.db_connection.execute(
"SELECT * from coin_record WHERE spent=? and confirmed_index<=? and wallet_id=? and coinbase=?",
(0, int(index), wallet_id, 1),
"SELECT * from coin_record WHERE spent=? and confirmed_height<=? and wallet_id=? and coinbase=?",
(0, int(height), wallet_id, 1),
)
coinbase_rows = await cursor_coinbase_coins.fetchall()
@ -205,8 +222,10 @@ class WalletCoinStore:
await cursor_regular_coins.close()
for row in list(coinbase_rows) + list(regular_rows):
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coins.add(
WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
)
return coins
# Checks DB and DiffStores for CoinRecords with puzzle_hash and returns them
@ -217,8 +236,10 @@ class WalletCoinStore:
rows = await cursor.fetchall()
await cursor.close()
for row in rows:
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coins.add(WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9]))
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coins.add(
WalletCoinRecord(coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11])
)
return list(coins)
async def get_coin_record_by_coin_id(self, coin_id: bytes32) -> Optional[WalletCoinRecord]:
@ -229,11 +250,13 @@ class WalletCoinStore:
if row is None:
return None
coin = Coin(bytes32(bytes.fromhex(row[6])), bytes32(bytes.fromhex(row[5])), row[7])
coin_record = WalletCoinRecord(coin, row[1], row[2], row[3], row[4], WalletType(row[8]), row[9])
coin = Coin(bytes32(bytes.fromhex(row[8])), bytes32(bytes.fromhex(row[7])), row[9])
coin_record = WalletCoinRecord(
coin, row[1], row[2], row[3], row[4], row[5], row[6], WalletType(row[10]), row[11]
)
return coin_record
async def rollback_to_block(self, block_index):
async def rollback_to_block(self, sub_height: uint32):
"""
Rolls back the blockchain to block_index. All blocks confirmed after this point
are removed from the LCA. All coins confirmed after this point are removed.
@ -242,29 +265,36 @@ class WalletCoinStore:
# Update memory cache
delete_queue: bytes32 = []
for coin_name, coin_record in self.coin_record_cache.items():
if coin_record.spent_block_index > block_index:
if coin_record.spent_block_sub_height > sub_height:
new_record = WalletCoinRecord(
coin_record.coin,
coin_record.confirmed_block_index,
coin_record.spent_block_index,
coin_record.confirmed_block_sub_height,
coin_record.confirmed_block_height,
coin_record.spent_block_sub_height,
coin_record.spent_block_height,
False,
coin_record.coinbase,
coin_record.wallet_type,
coin_record.wallet_id,
)
self.coin_record_cache[coin_record.coin.name().hex()] = new_record
if coin_record.confirmed_block_index > block_index:
if coin_record.confirmed_block_sub_height > sub_height:
delete_queue.append(coin_name)
for coin_name in delete_queue:
self.coin_record_cache.pop(coin_name)
# Delete from storage
c1 = await self.db_connection.execute("DELETE FROM coin_record WHERE confirmed_index>?", (block_index,))
c1 = await self.db_connection.execute("DELETE FROM coin_record WHERE confirmed_sub_height>?", (sub_height,))
await c1.close()
c2 = await self.db_connection.execute(
"UPDATE coin_record SET spent_index = 0, spent = 0 WHERE spent_index>?",
(block_index,),
"UPDATE coin_record SET spent_sub_height = 0, spent = 0 WHERE spent_sub_height>?",
(sub_height,),
)
c3 = await self.db_connection.execute(
"UPDATE coin_record SET spent_height = 0, spent = 0 WHERE spent_sub_height>?",
(sub_height,),
)
await c3.close()
await c2.close()
await self.db_connection.commit()

View File

@ -481,15 +481,31 @@ class WalletStateManager:
trade_additions,
) = await self.trade_manager.get_coins_of_interest()
trade_adds: List[Coin] = []
header_hash = self.blockchain.sub_height_to_hash[sub_height]
sub_block: SubBlockRecord = self.blockchain.sub_blocks[header_hash]
pool_rewards = set()
farmer_rewards = set()
farmer_rewards.add(bytes32(sub_block.sub_block_height.to_bytes(32, "big")))
pool_rewards.add(std_hash(std_hash(sub_block.sub_block_height)))
prev = self.blockchain.sub_blocks.get(sub_block.prev_hash, None)
while prev is not None:
pool_rewards.add(bytes32(prev.sub_block_height.to_bytes(32, "big")))
farmer_rewards.add(std_hash(std_hash(prev.sub_block_height)))
if prev.is_block:
break
prev = self.blockchain.sub_blocks[prev.prev_hash]
for coin in coins:
if coin.name() in trade_additions:
trade_adds.append(coin)
is_coinbase = False
is_fee_reward = False
if bytes32(height.to_bytes(32, "big")) == coin.parent_coin_info:
if coin.parent_coin_info in pool_rewards:
is_coinbase = True
if std_hash(std_hash(height)) == coin.parent_coin_info:
if coin.parent_coin_info in farmer_rewards:
is_fee_reward = True
info = await self.puzzle_store.wallet_info_for_puzzle_hash(coin.puzzle_hash)
@ -521,27 +537,27 @@ class WalletStateManager:
self.log.info(f"Coin:{coin.name()} NO RECORD")
continue
self.log.info(f"Coin:{coin.name()} Setting removed")
await self.coin_removed(coin, height, record.wallet_id)
await self.coin_removed(coin, height, sub_height, record.wallet_id)
return trade_coin_removed
async def coin_removed(self, coin: Coin, index: uint32, wallet_id: int):
async def coin_removed(self, coin: Coin, height: uint32, sub_height: uint32, wallet_id: int):
"""
Called when coin gets spent
"""
await self.coin_store.set_spent(coin.name(), index)
await self.coin_store.set_spent(coin.name(), sub_height, height)
unconfirmed_record: List[TransactionRecord] = await self.tx_store.unconfirmed_with_removal_coin(coin.name())
for unconfirmed in unconfirmed_record:
await self.tx_store.set_confirmed(unconfirmed.name(), index)
await self.tx_store.set_confirmed(unconfirmed.name(), sub_height, height)
self.state_changed("coin_removed", wallet_id)
async def coin_added(
self,
coin: Coin,
index: uint32,
height: uint32,
coinbase: bool,
fee_reward: bool,
wallet_id: uint32,
@ -551,7 +567,6 @@ class WalletStateManager:
"""
Adding coin to DB
"""
farm_reward = False
if coinbase or fee_reward:
farm_reward = True
@ -561,7 +576,8 @@ class WalletStateManager:
else:
type = TransactionType.FEE_REWARD.value
tx_record = TransactionRecord(
confirmed_at_index=uint32(index),
confirmed_at_sub_height=uint32(sub_height),
confirmed_at_height=uint32(height),
created_at_time=now,
to_puzzle_hash=coin.puzzle_hash,
amount=coin.amount,
@ -584,11 +600,12 @@ class WalletStateManager:
# This is the change from this transaction
for record in records:
if record.confirmed is False:
await self.tx_store.set_confirmed(record.name(), index)
await self.tx_store.set_confirmed(record.name(), sub_height, height)
else:
now = uint64(int(time.time()))
tx_record = TransactionRecord(
confirmed_at_index=uint32(index),
confirmed_at_sub_height=uint32(sub_height),
confirmed_at_height=uint32(height),
created_at_time=now,
to_puzzle_hash=coin.puzzle_hash,
amount=coin.amount,
@ -607,18 +624,18 @@ class WalletStateManager:
await self.tx_store.add_transaction_record(tx_record)
coin_record: WalletCoinRecord = WalletCoinRecord(
coin, index, uint32(0), False, farm_reward, wallet_type, wallet_id
coin, sub_height, height, uint32(0), uint32(0), False, farm_reward, wallet_type, wallet_id
)
await self.coin_store.add_coin_record(coin_record)
if wallet_type == WalletType.COLOURED_COIN:
wallet: CCWallet = self.wallets[wallet_id]
# TODO(straya): should this use height to hash instead of sub_height to hash
header_hash: bytes32 = self.blockchain.sub_height_to_hash[index]
header_hash: bytes32 = self.blockchain.sub_height_to_hash[height]
block: Optional[HeaderBlockRecord] = await self.block_store.get_header_block_record(header_hash)
assert block is not None
assert block.removals is not None
await wallet.coin_added(coin, index, header_hash, block.removals, sub_height)
await wallet.coin_added(coin, height, header_hash, block.removals, sub_height)
self.state_changed("coin_added", wallet_id)
@ -698,7 +715,7 @@ class WalletStateManager:
# Filter coins up to and including fork point
unspent_coin_names: Set[bytes32] = set()
for coin in my_coin_records_lca:
if coin.confirmed_block_index <= fork_h:
if coin.confirmed_block_sub_height <= fork_h:
unspent_coin_names.add(coin.name())
# # Get all blocks after fork point up to but not including this block
@ -792,18 +809,18 @@ class WalletStateManager:
return result
async def reorg_rollback(self, index: uint32):
async def reorg_rollback(self, sub_height: uint32):
"""
Rolls back and updates the coin_store and transaction store. It's possible this height
is the tip, or even beyond the tip.
"""
self.log.info(f"Rolling back to {index}")
self.log.info(f"Rolling back to sub_height: {sub_height}")
all_coins = await self.coin_store.get_all_coins()
self.log.info(f"all coins: {all_coins}")
await self.coin_store.rollback_to_block(index)
await self.coin_store.rollback_to_block(sub_height)
reorged: List[TransactionRecord] = await self.tx_store.get_transaction_above(index)
await self.tx_store.rollback_to_block(index)
reorged: List[TransactionRecord] = await self.tx_store.get_transaction_above(sub_height)
await self.tx_store.rollback_to_block(sub_height)
await self.retry_sending_after_reorg(reorged)

View File

@ -28,7 +28,8 @@ class WalletTransactionStore:
"CREATE TABLE IF NOT EXISTS transaction_record("
" transaction_record blob,"
" bundle_id text PRIMARY KEY,"
" confirmed_at_index bigint,"
" confirmed_at_sub_height bigint,"
" confirmed_at_height bigint,"
" created_at_time bigint,"
" to_puzzle_hash text,"
" amount bigint,"
@ -43,7 +44,10 @@ class WalletTransactionStore:
# Useful for reorg lookups
await self.db_connection.execute(
"CREATE INDEX IF NOT EXISTS tx_confirmed_index on transaction_record(confirmed_at_index)"
"CREATE INDEX IF NOT EXISTS tx_confirmed_index on transaction_record(confirmed_at_sub_height)"
)
await self.db_connection.execute(
"CREATE INDEX IF NOT EXISTS tx_confirmed_index on transaction_record(confirmed_at_height)"
)
await self.db_connection.execute(
@ -85,11 +89,12 @@ class WalletTransactionStore:
"""
cursor = await self.db_connection.execute(
"INSERT OR REPLACE INTO transaction_record VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
"INSERT OR REPLACE INTO transaction_record VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
(
bytes(record),
record.name().hex(),
record.confirmed_at_index,
record.confirmed_at_sub_height,
record.confirmed_at_height,
record.created_at_time,
record.to_puzzle_hash.hex(),
record.amount,
@ -109,7 +114,7 @@ class WalletTransactionStore:
first_in = list(self.tx_record_cache.keys())[0]
self.tx_record_cache.pop(first_in)
async def set_confirmed(self, id: bytes32, index: uint32):
async def set_confirmed(self, id: bytes32, sub_height: uint32, height: uint32):
"""
Updates transaction to be confirmed.
"""
@ -117,7 +122,8 @@ class WalletTransactionStore:
if current is None:
return
tx: TransactionRecord = TransactionRecord(
confirmed_at_index=index,
confirmed_at_sub_height=sub_height,
confirmed_at_height=height,
created_at_time=current.created_at_time,
to_puzzle_hash=current.to_puzzle_hash,
amount=current.amount,
@ -183,7 +189,8 @@ class WalletTransactionStore:
sent_to.append(append_data)
tx: TransactionRecord = TransactionRecord(
confirmed_at_index=current.confirmed_at_index,
confirmed_at_sub_height=current.confirmed_at_sub_height,
confirmed_at_height=current.confirmed_at_height,
created_at_time=current.created_at_time,
to_puzzle_hash=current.to_puzzle_hash,
amount=current.amount,
@ -211,7 +218,8 @@ class WalletTransactionStore:
if current is None:
return
tx: TransactionRecord = TransactionRecord(
confirmed_at_index=uint32(0),
confirmed_at_sub_height=uint32(0),
confirmed_at_height=uint32(0),
created_at_time=current.created_at_time,
to_puzzle_hash=current.to_puzzle_hash,
amount=current.amount,
@ -317,9 +325,9 @@ class WalletTransactionStore:
return records
async def get_transaction_above(self, height: uint32) -> List[TransactionRecord]:
async def get_transaction_above(self, sub_height: uint32) -> List[TransactionRecord]:
cursor = await self.db_connection.execute(
"SELECT * from transaction_record WHERE confirmed_at_index>?", (height,)
"SELECT * from transaction_record WHERE confirmed_at_sub_height>?", (sub_height,)
)
rows = await cursor.fetchall()
await cursor.close()
@ -331,10 +339,10 @@ class WalletTransactionStore:
return records
async def rollback_to_block(self, block_index):
async def rollback_to_block(self, sub_height):
# Delete from storage
c1 = await self.db_connection.execute(
"DELETE FROM transaction_record WHERE confirmed_at_index>?", (block_index,)
"DELETE FROM transaction_record WHERE confirmed_at_sub_height>?", (sub_height,)
)
await c1.close()
await self.db_connection.commit()