mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-09-20 16:08:51 +03:00
add sub height
This commit is contained in:
parent
4599093541
commit
c0ba32b488
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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),
|
||||
|
@ -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 = []
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user