Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bsv/auth/cert_encryption.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

def get_certificate_encryption_details(field_name: str, serial_number: Optional[str]) -> Tuple[dict, str]:
"""
TS/Go準拠の証明書フィールド暗号化メタデータを返す。
Returns certificate field encryption metadata compatible with TS/Go.
- protocol_id: {'protocol': 'certificate field encryption', 'security_level': 1}
- key_id: serial_numberがあれば "{serial_number} {field_name}", なければ field_name
- key_id: If serial_number is present, "{serial_number} {field_name}", otherwise field_name
"""
protocol_id = {
"protocol": "certificate field encryption",
Expand Down
2 changes: 1 addition & 1 deletion bsv/auth/certificate.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from bsv.keys import PublicKey, PrivateKey
from bsv.utils import unsigned_to_varint, Reader, Writer, serialize_ecdsa_der, deserialize_ecdsa_der, hash256

# Outpointの簡易表現
# Simple representation of Outpoint
class Outpoint(NamedTuple):
txid: str # 32byte hex string
index: int
Expand Down
8 changes: 4 additions & 4 deletions bsv/auth/requested_certificate_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ def items(self):
def is_empty(self):
return len(self.mapping) == 0

# --- 補助関数 ---
# --- Helper functions ---
def certifier_in_list(certifiers: List[PublicKey], certifier: Optional[PublicKey]) -> bool:
"""
Checks if the given certifier is in the list of certifiers.
Noneは常にFalse。
None is always False.
"""
if certifier is None:
return False
Expand All @@ -59,7 +59,7 @@ def certifier_in_list(certifiers: List[PublicKey], certifier: Optional[PublicKey
def is_empty_public_key(key: Optional[PublicKey]) -> bool:
"""
Checks if a PublicKey is empty/uninitialized.
Noneまたは内部バイト列が全てゼロの場合True。
Returns True if key is None or its internal byte array is all zeros.
"""
if key is None:
return True
Expand Down Expand Up @@ -108,7 +108,7 @@ def validate(self):
raise ValueError("empty or invalid certificate type specified")
if not fields:
raise ValueError(f"no fields specified for certificate type: {base64.b64encode(cert_type).decode('ascii')}")
# 追加: certifiersリストに未初期化公開鍵が含まれていないかチェック
# Addition: Check if the certifiers list contains any uninitialized public keys
for c in self.certifiers:
if is_empty_public_key(c):
raise ValueError("certifiers list contains an empty/uninitialized public key")
Expand Down
49 changes: 2 additions & 47 deletions bsv/broadcaster.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,2 @@
from abc import ABC, abstractmethod
from typing import Union, Dict, Any, TYPE_CHECKING


if TYPE_CHECKING:
from .transaction import Transaction

class BroadcastResponse:
def __init__(self, status: str, txid: str, message: str):
self.status = status
self.txid = txid
self.message = message


class BroadcastFailure:
def __init__(
self,
status: str,
code: str,
description: str,
txid: str = None,
more: Dict[str, Any] = None,
):
self.status = status
self.code = code
self.txid = txid
self.description = description
self.more = more


class Broadcaster(ABC):
def __init__(self):
self.URL = None

@abstractmethod
async def broadcast(
self, transaction: 'Transaction'
) -> Union[BroadcastResponse, BroadcastFailure]:
pass


def is_broadcast_response(r: Union[BroadcastResponse, BroadcastFailure]) -> bool:
return r.status == "success"


def is_broadcast_failure(r: Union[BroadcastResponse, BroadcastFailure]) -> bool:
return r.status == "error"
# DEPRECATED: Use bsv.broadcaster_core instead.
from bsv.broadcaster_core.broadcaster import *
2 changes: 2 additions & 0 deletions bsv/broadcaster_core/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# This file makes bsv.broadcaster a package.
from .broadcaster import Broadcaster, BroadcastResponse, BroadcastFailure
47 changes: 47 additions & 0 deletions bsv/broadcaster_core/broadcaster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
from abc import ABC, abstractmethod
from typing import Union, Dict, Any, TYPE_CHECKING


if TYPE_CHECKING:
from .transaction import Transaction

class BroadcastResponse:
def __init__(self, status: str, txid: str, message: str):
self.status = status
self.txid = txid
self.message = message


class BroadcastFailure:
def __init__(
self,
status: str,
code: str,
description: str,
txid: str = None,
more: Dict[str, Any] = None,
):
self.status = status
self.code = code
self.txid = txid
self.description = description
self.more = more


class Broadcaster(ABC):
def __init__(self):
self.URL = None

@abstractmethod
async def broadcast(
self, transaction: 'Transaction'
) -> Union[BroadcastResponse, BroadcastFailure]:
pass


def is_broadcast_response(r: Union[BroadcastResponse, BroadcastFailure]) -> bool:
return r.status == "success"


def is_broadcast_failure(r: Union[BroadcastResponse, BroadcastFailure]) -> bool:
return r.status == "error"
28 changes: 28 additions & 0 deletions bsv/broadcaster_core/whatsonchain.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import os
import requests

class WhatsOnChainBroadcaster:
"""
Broadcasts a raw transaction to the Bitcoin SV network via WhatsOnChain API.
Usage:
broadcaster = WhatsOnChainBroadcaster("main")
result = broadcaster.broadcast(tx_hex)
"""
def __init__(self, network="main"):
self.network = network
self.api_key = os.environ.get("WOC_API_KEY", "")
self.url = f"https://api.whatsonchain.com/v1/bsv/{self.network}/tx/raw"

def broadcast(self, tx_hex: str) -> dict:
headers = {"woc-api-key": self.api_key} if self.api_key else {}
try:
resp = requests.post(self.url, json={"txhex": tx_hex}, headers=headers, timeout=10)
resp.raise_for_status()
try:
data = resp.json()
return {"txid": data.get("txid") or data.get("data")}
except Exception:
# If not JSON, treat as raw txid string
return {"txid": resp.text.strip()}
except Exception as e:
return {"error": str(e), "response": getattr(resp, 'text', None)}
3 changes: 3 additions & 0 deletions bsv/broadcaster_plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .arc import ARC, ARCConfig
from .default import default_broadcaster
from .whatsonchain import WhatsOnChainBroadcaster
Loading