Resolving issues with transaction sending
This commit is contained in:
parent
5021b6c540
commit
c67b838e47
|
@ -41,7 +41,8 @@ URL_NONCE = 'https://{hostname}/{shard}blockchain/account/{address}'
|
||||||
MPC_DECIMALS = 10000
|
MPC_DECIMALS = 10000
|
||||||
|
|
||||||
|
|
||||||
def shard_id_for_address(address: str) -> str:
|
def shard_id_for_address(address: str | Address) -> str:
|
||||||
|
address = str(address)
|
||||||
# Very rough implementation
|
# Very rough implementation
|
||||||
if address is None:
|
if address is None:
|
||||||
msg = 'Address must not be None'
|
msg = 'Address must not be None'
|
||||||
|
@ -64,13 +65,18 @@ class SenderAuthentication:
|
||||||
secret_key: str
|
secret_key: str
|
||||||
|
|
||||||
def sender_address(self) -> Address:
|
def sender_address(self) -> Address:
|
||||||
return Address(self._signing_key().verifying_key.to_string())
|
derp = self._signing_key().verifying_key.to_string()
|
||||||
|
hashed = HashSha256.of_bytes(derp)
|
||||||
|
print(derp.hex())
|
||||||
|
print(derp)
|
||||||
|
print(hashed)
|
||||||
|
return Address(b'\0' + hashed._bytes[-20:])
|
||||||
|
|
||||||
def sign_hash(self, _hash: HashSha256) -> Signature:
|
def sign_hash(self, _hash: HashSha256) -> Signature:
|
||||||
return Signature(self._signing_key().sign(_hash.bytes))
|
return Signature(self._signing_key().sign(_hash._bytes))
|
||||||
|
|
||||||
def _signing_key(self):
|
def _signing_key(self):
|
||||||
return ecdsa.SigningKey.from_string(bytearray.fromhex(self.secret_key), curve=ecdsa.secp256k1)
|
return ecdsa.SigningKey.from_string(bytearray.fromhex(self.secret_key), curve=ecdsa.SECP256k1)
|
||||||
|
|
||||||
TRANSACTION_VALIDITY_DURATION = 60
|
TRANSACTION_VALIDITY_DURATION = 60
|
||||||
|
|
||||||
|
@ -79,7 +85,7 @@ def sign_transaction(
|
||||||
nonce: int,
|
nonce: int,
|
||||||
gas_cost: int,
|
gas_cost: int,
|
||||||
chain_id: str,
|
chain_id: str,
|
||||||
contract_address: str,
|
contract_address: Address | str,
|
||||||
transaction_rpc: bytes,
|
transaction_rpc: bytes,
|
||||||
) -> SignedTransaction:
|
) -> SignedTransaction:
|
||||||
sender = sender_authentication.sender_address
|
sender = sender_authentication.sender_address
|
||||||
|
@ -88,7 +94,7 @@ def sign_transaction(
|
||||||
inner: SignedTransactionInnerPart = SignedTransactionInnerPart(nonce,
|
inner: SignedTransactionInnerPart = SignedTransactionInnerPart(nonce,
|
||||||
valid_to_time,
|
valid_to_time,
|
||||||
gas_cost,
|
gas_cost,
|
||||||
Transaction(contract_address,
|
Transaction(Address.from_string(contract_address),
|
||||||
transaction_rpc))
|
transaction_rpc))
|
||||||
|
|
||||||
transaction_hash_bytes = inner.rpc_serialize() + chain_id.encode('utf8')
|
transaction_hash_bytes = inner.rpc_serialize() + chain_id.encode('utf8')
|
||||||
|
@ -104,6 +110,14 @@ class PbcClient:
|
||||||
sender_authentication: SenderAuthentication | None = None
|
sender_authentication: SenderAuthentication | None = None
|
||||||
hostname: str = HOSTNAME_MAINNET
|
hostname: str = HOSTNAME_MAINNET
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
assert isinstance(self.session, requests.Session)
|
||||||
|
assert isinstance(self.hostname, str)
|
||||||
|
|
||||||
|
if self.sender_authentication is not None:
|
||||||
|
assert isinstance(self.sender_authentication, SenderAuthentication)
|
||||||
|
|
||||||
|
|
||||||
def send_transaction(self, contract_address: str, rpc: bytes, gas_cost: int):
|
def send_transaction(self, contract_address: str, rpc: bytes, gas_cost: int):
|
||||||
if self.sender_authentication is None:
|
if self.sender_authentication is None:
|
||||||
msg = "PbcClient.sender_authentication required for send_transaction"
|
msg = "PbcClient.sender_authentication required for send_transaction"
|
||||||
|
@ -196,13 +210,13 @@ class PbcClient:
|
||||||
return Balances(date, mpc, byoc)
|
return Balances(date, mpc, byoc)
|
||||||
|
|
||||||
def get_chain_id(self) -> str:
|
def get_chain_id(self) -> str:
|
||||||
url = URL_NONCE.format(
|
url = URL_CHAIN_ID.format(
|
||||||
hostname=self.hostname,
|
hostname=self.hostname,
|
||||||
)
|
)
|
||||||
return self._get_json(url, method='GET')[0]['chainId']
|
return self._get_json(url, method='GET')[0]['chainId']
|
||||||
|
|
||||||
def get_sender_authentication_nonce(self) -> int:
|
def get_sender_authentication_nonce(self) -> int:
|
||||||
return self.get_nonce_for_account(self.sender_authentication.sender_address)
|
return self.get_nonce_for_account(self.sender_authentication.sender_address())
|
||||||
|
|
||||||
def get_nonce_for_account(self, address: str) -> int:
|
def get_nonce_for_account(self, address: str) -> int:
|
||||||
url = URL_NONCE.format(
|
url = URL_NONCE.format(
|
||||||
|
|
|
@ -22,27 +22,40 @@ class Address:
|
||||||
_bytes: bytes
|
_bytes: bytes
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
assert len(self._bytes) == 21
|
assert len(self._bytes) == 21, len(self._bytes)
|
||||||
|
|
||||||
def rpc_serialize(self) -> bytes:
|
def rpc_serialize(self) -> bytes:
|
||||||
return self._bytes
|
return self._bytes
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._bytes.hex()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_string(s: str) -> 'Address':
|
||||||
|
if isinstance(s, Address):
|
||||||
|
return s
|
||||||
|
return Address(bytes.fromhex(s))
|
||||||
|
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class Signature:
|
class Signature:
|
||||||
_bytes: bytes
|
_bytes: bytes
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
assert len(self._bytes) == 32
|
assert len(self._bytes) == 64, len(self._bytes)
|
||||||
|
|
||||||
def rpc_serialize(self) -> bytes:
|
def rpc_serialize(self) -> bytes:
|
||||||
return self._bytes
|
return self._bytes
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._bytes.hex()
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class HashSha256:
|
class HashSha256:
|
||||||
_bytes: bytes
|
_bytes: bytes
|
||||||
|
|
||||||
def __post_init__(self):
|
def __post_init__(self):
|
||||||
assert len(self._bytes) == 32
|
assert len(self._bytes) == 32, len(self._bytes)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def of_bytes(b: bytes) -> 'HashSha256':
|
def of_bytes(b: bytes) -> 'HashSha256':
|
||||||
|
@ -51,11 +64,17 @@ class HashSha256:
|
||||||
def rpc_serialize(self) -> bytes:
|
def rpc_serialize(self) -> bytes:
|
||||||
return self._bytes
|
return self._bytes
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return self._bytes.hex()
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class Transaction:
|
class Transaction:
|
||||||
contract_address: Address
|
contract_address: Address
|
||||||
transaction_rpc: bytes
|
transaction_rpc: bytes
|
||||||
|
|
||||||
|
def __post_init__(self):
|
||||||
|
assert isinstance(self.contract_address, Address), self.contract_address
|
||||||
|
|
||||||
def rpc_serialize(self) -> bytes:
|
def rpc_serialize(self) -> bytes:
|
||||||
return self.contract_address.rpc_serialize() + size_prefixed(self.transaction_rpc)
|
return self.contract_address.rpc_serialize() + size_prefixed(self.transaction_rpc)
|
||||||
|
|
||||||
|
@ -67,7 +86,7 @@ class SignedTransactionInnerPart:
|
||||||
transaction: Transaction
|
transaction: Transaction
|
||||||
|
|
||||||
def rpc_serialize(self) -> bytes:
|
def rpc_serialize(self) -> bytes:
|
||||||
return self.nonce.to_bytes(4, 'big') + self.valid_to_time.to_bytes(4, 'big') + self.gas_cost.to_bytes(4, 'big') + self.transaction.rpc_serialize()
|
return self.nonce.to_bytes(4, 'big') + self.valid_to_time.to_bytes(8, 'big') + self.gas_cost.to_bytes(8, 'big') + self.transaction.rpc_serialize()
|
||||||
|
|
||||||
@dataclasses.dataclass(frozen=True)
|
@dataclasses.dataclass(frozen=True)
|
||||||
class SignedTransaction:
|
class SignedTransaction:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user