mirror of
https://github.com/Chia-Network/chia-blockchain.git
synced 2024-11-11 01:28:17 +03:00
remove unnecessary index in CoinStore & add additional benchmarks (#8641)
* simplify and extend the coin store benchmark to include lookups by coin ID and get_coin_removed_at_height * remove coin_spent index from coin store table. It's not necessary and slows down updates (and caused one mistaken query plan)
This commit is contained in:
parent
653a11476c
commit
bbc2f76a21
@ -4,7 +4,7 @@ import secrets
|
||||
from time import time
|
||||
from pathlib import Path
|
||||
from chia.full_node.coin_store import CoinStore
|
||||
from typing import List
|
||||
from typing import List, Tuple
|
||||
import os
|
||||
import sys
|
||||
|
||||
@ -14,11 +14,14 @@ from chia.consensus.coinbase import create_farmer_coin, create_pool_coin
|
||||
from chia.consensus.default_constants import DEFAULT_CONSTANTS
|
||||
from chia.types.blockchain_format.sized_bytes import bytes32
|
||||
from chia.types.blockchain_format.coin import Coin
|
||||
from chia.util.ints import uint64
|
||||
from chia.util.ints import uint64, uint32
|
||||
|
||||
|
||||
NUM_ITERS = 200
|
||||
|
||||
# farmer puzzle hash
|
||||
ph = bytes32(b"a" * 32)
|
||||
|
||||
|
||||
async def setup_db() -> DBWrapper:
|
||||
db_filename = Path("coin-store-benchmark.db")
|
||||
@ -40,46 +43,57 @@ def make_coin() -> Coin:
|
||||
return Coin(rand_hash(), rand_hash(), uint64(1))
|
||||
|
||||
|
||||
def make_coins(num: int) -> Tuple[List[Coin], List[bytes32]]:
|
||||
additions: List[Coin] = []
|
||||
hashes: List[bytes32] = []
|
||||
for i in range(num):
|
||||
c = make_coin()
|
||||
additions.append(c)
|
||||
hashes.append(c.get_hash())
|
||||
|
||||
return additions, hashes
|
||||
|
||||
|
||||
def rewards(height: uint32) -> Tuple[Coin, Coin]:
|
||||
farmer_coin = create_farmer_coin(height, ph, uint64(250000000), DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
pool_coin = create_pool_coin(height, ph, uint64(1750000000), DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
return farmer_coin, pool_coin
|
||||
|
||||
|
||||
async def run_new_block_benchmark():
|
||||
|
||||
db_wrapper: DBWrapper = await setup_db()
|
||||
|
||||
try:
|
||||
coin_store = await CoinStore.create(db_wrapper)
|
||||
# farmer puzzle hash
|
||||
ph = bytes32(b"a" * 32)
|
||||
|
||||
all_added: List[bytes32] = []
|
||||
all_unspent: List[bytes32] = []
|
||||
all_coins: List[bytes32] = []
|
||||
|
||||
block_height = 1
|
||||
timestamp = 1631794488
|
||||
|
||||
print("Building database ", end="")
|
||||
for height in range(block_height, block_height + NUM_ITERS):
|
||||
additions = []
|
||||
removals = []
|
||||
|
||||
# add some new coins
|
||||
for i in range(2000):
|
||||
c = make_coin()
|
||||
additions.append(c)
|
||||
all_added.append(c.get_hash())
|
||||
additions, hashes = make_coins(2000)
|
||||
|
||||
# farm rewards
|
||||
farmer_coin = create_farmer_coin(height, ph, 250000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
pool_coin = create_pool_coin(height, ph, 1750000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
reward_coins = [pool_coin, farmer_coin]
|
||||
all_added += [pool_coin.name(), farmer_coin.name()]
|
||||
farmer_coin, pool_coin = rewards(height)
|
||||
all_coins += hashes
|
||||
all_unspent += hashes
|
||||
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
||||
|
||||
# remove some coins we've added previously
|
||||
random.shuffle(all_added)
|
||||
removals = all_added[:100]
|
||||
all_added = all_added[100:]
|
||||
random.shuffle(all_unspent)
|
||||
removals = all_unspent[:100]
|
||||
all_unspent = all_unspent[100:]
|
||||
|
||||
await coin_store.new_block(
|
||||
height,
|
||||
timestamp,
|
||||
set(reward_coins),
|
||||
set([pool_coin, farmer_coin]),
|
||||
additions,
|
||||
removals,
|
||||
)
|
||||
@ -97,33 +111,28 @@ async def run_new_block_benchmark():
|
||||
total_remove = 0
|
||||
print("\nProfiling mostly additions ", end="")
|
||||
for height in range(block_height, block_height + NUM_ITERS):
|
||||
additions = []
|
||||
removals = []
|
||||
|
||||
# add some new coins
|
||||
for i in range(2000):
|
||||
c = make_coin()
|
||||
additions.append(c)
|
||||
all_added.append(c.get_hash())
|
||||
additions, hashes = make_coins(2000)
|
||||
total_add += 2000
|
||||
|
||||
farmer_coin = create_farmer_coin(height, ph, 250000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
pool_coin = create_pool_coin(height, ph, 1750000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
reward_coins = [pool_coin, farmer_coin]
|
||||
all_added += [pool_coin.name(), farmer_coin.name()]
|
||||
farmer_coin, pool_coin = rewards(height)
|
||||
all_coins += hashes
|
||||
all_unspent += hashes
|
||||
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
||||
total_add += 2
|
||||
|
||||
# remove some coins we've added previously
|
||||
random.shuffle(all_added)
|
||||
removals = all_added[:100]
|
||||
all_added = all_added[100:]
|
||||
random.shuffle(all_unspent)
|
||||
removals = all_unspent[:100]
|
||||
all_unspent = all_unspent[100:]
|
||||
total_remove += 100
|
||||
|
||||
start = time()
|
||||
await coin_store.new_block(
|
||||
height,
|
||||
timestamp,
|
||||
set(reward_coins),
|
||||
set([pool_coin, farmer_coin]),
|
||||
additions,
|
||||
removals,
|
||||
)
|
||||
@ -147,31 +156,29 @@ async def run_new_block_benchmark():
|
||||
total_time = 0
|
||||
for height in range(block_height, block_height + NUM_ITERS):
|
||||
additions = []
|
||||
removals = []
|
||||
|
||||
# add one new coins
|
||||
c = make_coin()
|
||||
additions.append(c)
|
||||
all_added.append(c.get_hash())
|
||||
total_add += 1
|
||||
|
||||
farmer_coin = create_farmer_coin(height, ph, 250000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
pool_coin = create_pool_coin(height, ph, 1750000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
reward_coins = [pool_coin, farmer_coin]
|
||||
all_added += [pool_coin.name(), farmer_coin.name()]
|
||||
farmer_coin, pool_coin = rewards(height)
|
||||
all_coins += [c.get_hash()]
|
||||
all_unspent += [c.get_hash()]
|
||||
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
||||
total_add += 2
|
||||
|
||||
# remove some coins we've added previously
|
||||
random.shuffle(all_added)
|
||||
removals = all_added[:700]
|
||||
all_added = all_added[700:]
|
||||
random.shuffle(all_unspent)
|
||||
removals = all_unspent[:700]
|
||||
all_unspent = all_unspent[700:]
|
||||
total_remove += 700
|
||||
|
||||
start = time()
|
||||
await coin_store.new_block(
|
||||
height,
|
||||
timestamp,
|
||||
set(reward_coins),
|
||||
set([pool_coin, farmer_coin]),
|
||||
additions,
|
||||
removals,
|
||||
)
|
||||
@ -195,33 +202,28 @@ async def run_new_block_benchmark():
|
||||
total_remove = 0
|
||||
total_time = 0
|
||||
for height in range(block_height, block_height + NUM_ITERS):
|
||||
additions = []
|
||||
removals = []
|
||||
|
||||
# add some new coins
|
||||
for i in range(2000):
|
||||
c = make_coin()
|
||||
additions.append(c)
|
||||
all_added.append(c.get_hash())
|
||||
additions, hashes = make_coins(2000)
|
||||
total_add += 2000
|
||||
|
||||
farmer_coin = create_farmer_coin(height, ph, 250000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
pool_coin = create_pool_coin(height, ph, 1750000000, DEFAULT_CONSTANTS.GENESIS_CHALLENGE)
|
||||
reward_coins = [pool_coin, farmer_coin]
|
||||
all_added += [pool_coin.name(), farmer_coin.name()]
|
||||
farmer_coin, pool_coin = rewards(height)
|
||||
all_coins += hashes
|
||||
all_unspent += hashes
|
||||
all_unspent += [pool_coin.name(), farmer_coin.name()]
|
||||
total_add += 2
|
||||
|
||||
# remove some coins we've added previously
|
||||
random.shuffle(all_added)
|
||||
removals = all_added[:2000]
|
||||
all_added = all_added[2000:]
|
||||
random.shuffle(all_unspent)
|
||||
removals = all_unspent[:2000]
|
||||
all_unspent = all_unspent[2000:]
|
||||
total_remove += 2000
|
||||
|
||||
start = time()
|
||||
await coin_store.new_block(
|
||||
height,
|
||||
timestamp,
|
||||
set(reward_coins),
|
||||
set([pool_coin, farmer_coin]),
|
||||
additions,
|
||||
removals,
|
||||
)
|
||||
@ -235,8 +237,62 @@ async def run_new_block_benchmark():
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
block_height += NUM_ITERS
|
||||
|
||||
print(f"\nFULLBLOCKS, time: {total_time:0.4f}s additions: {total_add} removals: {total_remove}")
|
||||
|
||||
print("profiling get_coin_records_by_names, include_spent ", end="")
|
||||
total_time = 0
|
||||
found_coins = 0
|
||||
for i in range(NUM_ITERS):
|
||||
lookup = random.sample(all_coins, 200)
|
||||
start = time()
|
||||
records = await coin_store.get_coin_records_by_names(True, lookup)
|
||||
total_time += time() - start
|
||||
assert len(records) == 200
|
||||
found_coins += len(records)
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
print(
|
||||
f"\nGET RECORDS BY NAMES with spent, time: {total_time:0.4f}s {NUM_ITERS} "
|
||||
f"lookups found {found_coins} coins in total"
|
||||
)
|
||||
|
||||
print("profiling get_coin_records_by_names, without spent coins ", end="")
|
||||
total_time = 0
|
||||
found_coins = 0
|
||||
for i in range(NUM_ITERS):
|
||||
lookup = random.sample(all_coins, 200)
|
||||
start = time()
|
||||
records = await coin_store.get_coin_records_by_names(False, lookup)
|
||||
total_time += time() - start
|
||||
assert len(records) <= 200
|
||||
found_coins += len(records)
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
print(
|
||||
f"\nGET RECORDS BY NAMES without spent, time: {total_time:0.4f}s {NUM_ITERS} "
|
||||
f"lookups found {found_coins} coins in total"
|
||||
)
|
||||
|
||||
print("profiling get_coin_removed_at_height ", end="")
|
||||
total_time = 0
|
||||
found_coins = 0
|
||||
for i in range(1, block_height):
|
||||
start = time()
|
||||
records = await coin_store.get_coins_removed_at_height(i)
|
||||
total_time += time() - start
|
||||
found_coins += len(records)
|
||||
print(".", end="")
|
||||
sys.stdout.flush()
|
||||
|
||||
print(
|
||||
f"\nGET COINS REMOVED AT HEIGHT, time: {total_time:0.4f}s {block_height-1} blocks, "
|
||||
f"found {found_coins} coins in total"
|
||||
)
|
||||
|
||||
finally:
|
||||
await db_wrapper.db.close()
|
||||
|
||||
|
@ -55,7 +55,10 @@ class CoinStore:
|
||||
|
||||
await self.coin_record_db.execute("CREATE INDEX IF NOT EXISTS coin_spent_index on coin_record(spent_index)")
|
||||
|
||||
await self.coin_record_db.execute("CREATE INDEX IF NOT EXISTS coin_spent on coin_record(spent)")
|
||||
# earlier versions of chia created this index despite no lookups needing
|
||||
# it. For now, just don't create it for new installs. In the future we
|
||||
# may remove the index from existing installations as well
|
||||
# await self.coin_record_db.execute("DROP INDEX IF EXISTS coin_spent")
|
||||
|
||||
await self.coin_record_db.execute("CREATE INDEX IF NOT EXISTS coin_puzzle_hash on coin_record(puzzle_hash)")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user