Skip to content

Commit

Permalink
use rust version of SpendBundle
Browse files Browse the repository at this point in the history
  • Loading branch information
arvidn committed May 7, 2024
1 parent fdb87e6 commit 5efb6ea
Show file tree
Hide file tree
Showing 7 changed files with 13 additions and 84 deletions.
15 changes: 1 addition & 14 deletions chia/_tests/core/custom_types/test_spend_bundle.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
from chia.types.coin_spend import CoinSpend, make_spend
from chia.types.condition_opcodes import ConditionOpcode
from chia.types.spend_bundle import SpendBundle
from chia.util.errors import ValidationError
from chia.util.ints import uint64

BLANK_SPEND_BUNDLE = SpendBundle(coin_spends=[], aggregated_signature=G2Element())
Expand All @@ -29,18 +28,6 @@ def test_round_trip(self):

assert sb == spend_bundle

def test_round_trip_with_legacy_key_parsing(self):
spend_bundle = BLANK_SPEND_BUNDLE
json_dict = spend_bundle.to_json_dict()
json_dict["coin_solutions"] = None
SpendBundle.from_json_dict(json_dict) # testing no error because parser just looks at "coin_spends"
json_dict["coin_solutions"] = json_dict["coin_spends"]
del json_dict["coin_spends"]

sb = SpendBundle.from_json_dict(json_dict)

assert sb == spend_bundle


def rand_hash(rng: random.Random) -> bytes32:
ret = bytearray(32)
Expand Down Expand Up @@ -80,5 +67,5 @@ def test_compute_additions_create_coin_max_cost() -> None:
# make a large number of CoinSpends
spends, _ = create_spends(6111)
sb = SpendBundle(spends, G2Element())
with pytest.raises(ValidationError, match="BLOCK_COST_EXCEEDS_MAX"):
with pytest.raises(ValueError, match="cost exceeded"):
sb.additions()
2 changes: 1 addition & 1 deletion chia/_tests/core/mempool/test_mempool.py
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ async def test_invalid_signature(self, one_node_one_block, wallet_a):

sb: SpendBundle = generate_test_spend_bundle(wallet_a, coin1)
assert sb.aggregated_signature != G2Element.generator()
sb = dataclasses.replace(sb, aggregated_signature=G2Element.generator())
sb = sb.replace(aggregated_signature=G2Element.generator())
res: Optional[Message] = await self.send_sb(full_node_1, sb)
assert res is not None
ack: TransactionAck = TransactionAck.from_bytes(res.data)
Expand Down
3 changes: 1 addition & 2 deletions chia/_tests/fee_estimation/test_fee_estimation_rpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.types.spend_bundle import SpendBundle
from chia.util.ints import uint64
from chia.util.streamable import InvalidTypeError


@pytest.fixture(scope="function")
Expand Down Expand Up @@ -157,7 +156,7 @@ async def test_cost_invalid_type(setup_node_and_rpc: Tuple[FullNodeRpcClient, Fu
@pytest.mark.anyio
async def test_tx_invalid_type(setup_node_and_rpc: Tuple[FullNodeRpcClient, FullNodeRpcApi]) -> None:
client, full_node_rpc_api = setup_node_and_rpc
with pytest.raises(InvalidTypeError):
with pytest.raises(TypeError):
await full_node_rpc_api.get_fee_estimate({"target_times": [], "spend_bundle": {"coin_spends": 1}})


Expand Down
2 changes: 1 addition & 1 deletion chia/_tests/wallet/cat_wallet/test_trades.py
Original file line number Diff line number Diff line change
Expand Up @@ -1822,7 +1822,7 @@ async def test_trade_bad_spend(wallets_prefarm):
assert trade_make is not None
peer = wallet_node_taker.get_full_node_peer()
offer = Offer.from_bytes(trade_make.offer)
bundle = dataclasses.replace(offer._bundle, aggregated_signature=G2Element())
bundle = offer._bundle.replace(aggregated_signature=G2Element())
offer = dataclasses.replace(offer, _bundle=bundle)
tr1, txs1 = await trade_manager_taker.respond_to_offer(offer, peer, DEFAULT_TX_CONFIG, fee=uint64(10))
await trade_manager_taker.wallet_state_manager.add_pending_transactions(txs1)
Expand Down
5 changes: 2 additions & 3 deletions chia/data_layer/data_layer_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ async def create_update_state_spend(
spend_bundle = SpendBundle([coin_spend], G2Element())

if announce_new_state:
spend_bundle = dataclasses.replace(spend_bundle, coin_spends=[coin_spend, second_coin_spend])
spend_bundle = spend_bundle.replace(coin_spends=[coin_spend, second_coin_spend])

dl_tx = TransactionRecord(
confirmed_at_height=uint32(0),
Expand Down Expand Up @@ -1210,8 +1210,7 @@ async def make_update_offer(
new_solution: Program = dl_solution.replace(rrffrf=new_graftroot, rrffrrf=Program.to([None] * 5))
new_spend: CoinSpend = dl_spend.replace(solution=SerializedProgram.from_program(new_solution))
signed_bundle = await dl_wallet.sign(new_spend)
new_bundle: SpendBundle = dataclasses.replace(
txs[0].spend_bundle,
new_bundle: SpendBundle = txs[0].spend_bundle.replace(
coin_spends=all_other_spends,
)
agg_bundle: SpendBundle = SpendBundle.aggregate([signed_bundle, new_bundle])
Expand Down
63 changes: 3 additions & 60 deletions chia/types/spend_bundle.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,13 @@
from __future__ import annotations

from dataclasses import dataclass
from typing import Any, Dict, List

from chia_rs import AugSchemeMPL, G2Element
import chia_rs

from chia.consensus.default_constants import DEFAULT_CONSTANTS
from chia.types.blockchain_format.coin import Coin
from chia.types.blockchain_format.sized_bytes import bytes32
from chia.util.errors import Err, ValidationError
from chia.util.streamable import Streamable, streamable, streamable_from_dict
from chia.wallet.util.debug_spend_bundle import debug_spend_bundle

from .coin_spend import CoinSpend, compute_additions_with_cost


@streamable
@dataclass(frozen=True)
class SpendBundle(Streamable):
"""
This is a list of coins being spent along with their solution programs, and a single
aggregated signature. This is the object that most closely corresponds to a bitcoin
transaction (although because of non-interactive signature aggregation, the boundaries
between transactions are more flexible than in bitcoin).
"""

coin_spends: List[CoinSpend]
aggregated_signature: G2Element

@classmethod
def aggregate(cls, spend_bundles: List[SpendBundle]) -> SpendBundle:
coin_spends: List[CoinSpend] = []
sigs: List[G2Element] = []
for bundle in spend_bundles:
coin_spends += bundle.coin_spends
sigs.append(bundle.aggregated_signature)
aggregated_signature = AugSchemeMPL.aggregate(sigs)
return cls(coin_spends, aggregated_signature)

# TODO: this should be removed
def additions(self, *, max_cost: int = DEFAULT_CONSTANTS.MAX_BLOCK_COST_CLVM) -> List[Coin]:
items: List[Coin] = []
for cs in self.coin_spends:
coins, cost = compute_additions_with_cost(cs, max_cost=max_cost)
max_cost -= cost
if max_cost < 0:
raise ValidationError(Err.BLOCK_COST_EXCEEDS_MAX, "additions() for SpendBundle")
items.extend(coins)
return items

def removals(self) -> List[Coin]:
return [_.coin for _ in self.coin_spends]

def name(self) -> bytes32:
return self.get_hash()

def debug(self, agg_sig_additional_data: bytes32 = DEFAULT_CONSTANTS.AGG_SIG_ME_ADDITIONAL_DATA) -> None:
debug_spend_bundle(self, agg_sig_additional_data)
from .coin_spend import compute_additions_with_cost

@classmethod
def from_json_dict(cls, json_dict: Dict[str, Any]) -> SpendBundle:
if "coin_solutions" in json_dict and "coin_spends" not in json_dict:
json_dict = dict(
aggregated_signature=json_dict["aggregated_signature"], coin_spends=json_dict["coin_solutions"]
)
return streamable_from_dict(cls, json_dict)
SpendBundle = chia_rs.SpendBundle


# This function executes all the puzzles to compute the difference between
Expand Down
7 changes: 4 additions & 3 deletions chia/wallet/trading/offer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from chia.util.bech32m import bech32_decode, bech32_encode, convertbits
from chia.util.errors import Err, ValidationError
from chia.util.ints import uint64
from chia.util.streamable import parse_rust
from chia.wallet.conditions import (
AssertCoinAnnouncement,
AssertPuzzleAnnouncement,
Expand Down Expand Up @@ -683,12 +684,12 @@ def from_bech32(cls, offer_bech32: str) -> Offer:
# We basically hijack the SpendBundle versions for most of it
@classmethod
def parse(cls, f: BinaryIO) -> Offer:
parsed_bundle = SpendBundle.parse(f)
parsed_bundle = parse_rust(f, SpendBundle)
return cls.from_bytes(bytes(parsed_bundle))

def stream(self, f: BinaryIO) -> None:
as_spend_bundle = SpendBundle.from_bytes(bytes(self))
as_spend_bundle.stream(f)
spend_bundle_bytes = self.to_spend_bundle().to_bytes()
f.write(spend_bundle_bytes)

def __bytes__(self) -> bytes:
return bytes(self.to_spend_bundle())
Expand Down

0 comments on commit 5efb6ea

Please sign in to comment.