Skip to content

Commit da10459

Browse files
authored
Merge pull request #33 from ainblockchain/release/v1.1.0
Release/v1.1.0
2 parents 3c31720 + 1831b48 commit da10459

13 files changed

+907
-145
lines changed

README.md

+26-5
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,12 @@
22

33
A python version of [ain-js](https://www.npmjs.com/package/@ainblockchain/ain-js).
44

5+
56
## Installation
67
```
78
pip install ain-py
89
```
910

10-
## Run all test
11-
```
12-
tox
13-
```
1411

1512
## Examples
1613
```python
@@ -25,4 +22,28 @@ async def process():
2522

2623
loop = asyncio.get_event_loop()
2724
loop.run_until_complete(process())
28-
```
25+
```
26+
27+
28+
## Test How-To
29+
1. Clone AIN Blockchain and install
30+
```
31+
git clone [email protected]:ainblockchain/ain-blockchain.git
32+
yarn install
33+
```
34+
35+
2. Start blockchain locally
36+
```
37+
bash start_local_blockchain.sh
38+
```
39+
40+
3. Run tests
41+
```
42+
tox
43+
```
44+
45+
46+
## License
47+
48+
This project is licensed under the MIT License
49+

ain/ain.py

+33-109
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import asyncio
21
from typing import List, Any, Union
32
from ain.provider import Provider
43
from ain.net import Network
54
from ain.wallet import Wallet
65
from ain.types import AinOptions, TransactionInput, TransactionBody, ValueOnlyTransactionInput
76
from ain.db import Database
7+
from ain.signer import Signer
8+
from ain.signer.default_signer import DefaultSigner
89
from ain.utils import getTimestamp, toChecksumAddress
910

1011
class Ain:
@@ -28,6 +29,8 @@ class Ain:
2829
"""The `Network` instance."""
2930
wallet: Wallet
3031
"""The `Wallet` instance."""
32+
signer: Signer
33+
"""The `Signer` instance."""
3134

3235
def __init__(self, providerUrl: str, chainId: int = 0, ainOptions: AinOptions = AinOptions()):
3336
self.provider = Provider(self, providerUrl)
@@ -36,6 +39,7 @@ def __init__(self, providerUrl: str, chainId: int = 0, ainOptions: AinOptions =
3639
self.net = Network(self.provider)
3740
self.wallet = Wallet(self, self.chainId)
3841
self.db = Database(self, self.provider)
42+
self.signer = DefaultSigner(self.wallet, self.provider)
3943

4044
def setProvider(self, providerUrl: str, chainId: int = 0):
4145
"""Sets a new provider
@@ -50,6 +54,14 @@ def setProvider(self, providerUrl: str, chainId: int = 0):
5054
self.wallet.chainId = chainId
5155
self.db = Database(self, self.provider)
5256

57+
def setSigner(self, signer: Signer):
58+
"""Sets a new signer
59+
60+
Args:
61+
signer (Signer): The signer to set.
62+
"""
63+
self.signer = signer
64+
5365
# TODO(kriii): Return objects typing.
5466

5567
async def getBlock(
@@ -141,9 +153,7 @@ async def getTransaction(self, transactionHash: str) -> Any:
141153
Returns:
142154
The transaction with the given transaction hash.
143155
"""
144-
return await self.provider.send(
145-
"ain_getTransactionByHash", {"hash": transactionHash}
146-
)
156+
return await self.provider.send("ain_getTransactionByHash", {"hash": transactionHash})
147157

148158
async def getStateUsage(self, appName: str) -> Any:
149159
"""Gets a state usage with the given app name.
@@ -154,9 +164,7 @@ async def getStateUsage(self, appName: str) -> Any:
154164
Returns:
155165
The state usage with the given app name.
156166
"""
157-
return await self.provider.send(
158-
"ain_getStateUsage", {"app_name": appName}
159-
)
167+
return await self.provider.send("ain_getStateUsage", {"app_name": appName})
160168

161169
async def validateAppName(self, appName: str) -> Any:
162170
"""Validate a given app name.
@@ -167,56 +175,43 @@ async def validateAppName(self, appName: str) -> Any:
167175
Returns:
168176
The validity of the given app name.
169177
"""
170-
return await self.provider.send(
171-
"ain_validateAppName", {"app_name": appName}
172-
)
178+
return await self.provider.send("ain_validateAppName", {"app_name": appName})
173179

174-
async def sendTransaction(self, transactionObject: TransactionInput) -> Any:
175-
"""Signs and sends the transaction to the network.
180+
async def sendTransaction(self, transactionObject: TransactionInput, isDryrun = False) -> Any:
181+
"""Signs and sends a transaction to the network.
176182
177183
Args:
178-
transactionObject (TransactionInput): The transaction.
184+
transactionObject (TransactionInput): The transaction input object.
185+
isDryrun (bool): The dryrun option.
179186
180187
Returns:
181-
The transaction result.
188+
The return value of the blockchain API.
182189
"""
183-
txBody = await self.buildTransactionBody(transactionObject)
184-
signature = self.wallet.signTransaction(
185-
txBody, getattr(transactionObject, "address", None)
186-
)
187-
return await self.sendSignedTransaction(signature, txBody)
190+
return await self.signer.sendTransaction(transactionObject, isDryrun)
188191

189-
async def sendSignedTransaction(self, signature: str, txBody: TransactionBody) -> Any:
192+
async def sendSignedTransaction(self, signature: str, txBody: TransactionBody, isDryrun = False) -> Any:
190193
"""Sends a signed transaction to the network.
191194
192195
Args:
193-
signature (str): The signature of the transaction.
196+
signature (str): The signature.
194197
txBody (TransactionBody): The transaction body.
198+
isDryrun (bool): The dryrun option.
195199
196200
Returns:
197-
The transaction result.
201+
The return value of the blockchain API.
198202
"""
199-
return await self.provider.send(
200-
"ain_sendSignedTransaction", {"signature": signature, "tx_body": txBody}
201-
)
203+
return await self.signer.sendSignedTransaction(signature, txBody, isDryrun)
202204

203205
async def sendTransactionBatch(self, transactionObjects: List[TransactionInput]) -> List[Any]:
204-
"""Sends a signed transactions to the network.
206+
"""Signs and sends multiple transactions in a batch to the network.
205207
206208
Args:
207-
transactionObjects (List[TransactionInput]): The list of the transactions.
209+
transactionObjects (List[TransactionInput]): The list of the transaction input objects.
208210
209211
Returns:
210-
The transaction results.
212+
The return value of the blockchain API.
211213
"""
212-
txListCoroutines = []
213-
for txInput in transactionObjects:
214-
txListCoroutines.append(self.__buildSignedTransaction(txInput))
215-
216-
txList = await asyncio.gather(*txListCoroutines)
217-
return await self.provider.send(
218-
"ain_sendSignedTransactionBatch", {"tx_list": txList}
219-
)
214+
return await self.signer.sendTransactionBatch(transactionObjects)
220215

221216
def depositConsensusStake(self, input: ValueOnlyTransactionInput) -> Any:
222217
"""Sends a transaction that deposits AIN for consensus staking.
@@ -251,69 +246,11 @@ async def getConsensusStakeAmount(self, account: str = None) -> Any:
251246
The amount of the AIN of that address.
252247
"""
253248
if account is None:
254-
address = self.wallet.getImpliedAddress()
249+
address = self.signer.getAddress()
255250
else:
256251
address = toChecksumAddress(account)
257252
return await self.db.ref(f"/deposit_accounts/consensus/{address}").getValue()
258253

259-
async def getNonce(self, args: dict) -> Any:
260-
"""Gets a current transaction count of account, which is the nonce of the account.
261-
262-
Args:
263-
args (dict): May contain a string 'address' and a string 'from' values.
264-
The 'address' indicates the address of the account to get the
265-
nonce of, and the 'from' indicates where to get the nonce from.
266-
It could be either the pending transaction pool ("pending") or
267-
the committed blocks ("committed"). The default value is "committed".
268-
269-
Returns:
270-
The nonce of the account.
271-
"""
272-
params = dict(args)
273-
if "address" in args:
274-
params["address"] = toChecksumAddress(args["address"])
275-
else:
276-
params["address"] = self.wallet.getImpliedAddress()
277-
278-
if "from" in args:
279-
if args["from"] != "pending" and args["from"] != "committed":
280-
raise ValueError("'from' should be either 'pending' or 'committed'")
281-
282-
ret = await self.provider.send("ain_getNonce", params)
283-
return ret
284-
285-
async def buildTransactionBody(
286-
self, transactionInput: TransactionInput
287-
) -> TransactionBody:
288-
"""Builds a transaction body from the transaction input.
289-
290-
Args:
291-
transactionInput (TransactionInput): The transaction input.
292-
293-
Returns:
294-
TransactionBody: The builded transaction body.
295-
"""
296-
address = self.wallet.getImpliedAddress(
297-
getattr(transactionInput, "address", None)
298-
)
299-
operation = transactionInput.operation
300-
parent_tx_hash = getattr(transactionInput, "parent_tx_hash", None)
301-
nonce = getattr(transactionInput, "nonce", None)
302-
if nonce is None:
303-
nonce = await self.getNonce({"address": address, "from": "pending"})
304-
timestamp = getattr(transactionInput, "timestamp", getTimestamp())
305-
gas_price = getattr(transactionInput, "gas_price", 0)
306-
billing = getattr(transactionInput, "billing", None)
307-
308-
return TransactionBody(
309-
operation=operation,
310-
parent_tx_hash=parent_tx_hash,
311-
nonce=nonce,
312-
timestamp=timestamp,
313-
gas_price=gas_price,
314-
billing=billing,
315-
)
316-
317254
def __stakeFunction(self, path: str, input: ValueOnlyTransactionInput) -> Any:
318255
"""A base function for all staking related database changes. It builds a
319256
deposit/withdraw transaction and sends the transaction by calling sendTransaction().
@@ -322,20 +259,7 @@ def __stakeFunction(self, path: str, input: ValueOnlyTransactionInput) -> Any:
322259
raise ValueError("a value should be specified.")
323260
if type(input.value) is not int:
324261
raise ValueError("value has to be a int.")
325-
input.address = self.wallet.getImpliedAddress(getattr(input, "address", None))
262+
input.address = self.signer.getAddress(getattr(input, "address", None))
326263
ref = self.db.ref(f'{path}/{input.address}').push()
327264
input.ref = "value"
328265
return ref.setValue(input)
329-
330-
async def __buildSignedTransaction(self, transactionObject: TransactionInput) -> dict:
331-
"""Returns a builded transaction with the signature"""
332-
txBody = await self.buildTransactionBody(transactionObject)
333-
if not hasattr(transactionObject, "nonce"):
334-
# Batch transactions' nonces should be specified.
335-
# If they're not, they default to un-nonced (nonce = -1).
336-
txBody.nonce = -1
337-
338-
signature = self.wallet.signTransaction(
339-
txBody, getattr(transactionObject, "address", None)
340-
)
341-
return {"signature": signature, "tx_body": txBody}

0 commit comments

Comments
 (0)