Skip to content

Commit e831740

Browse files
committed
Merge branch 'release/v1.17.0'
2 parents 9964004 + d59f89b commit e831740

21 files changed

+724
-829
lines changed

.test-env

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Configs for testing repo download:
2+
SDK_TESTING_URL="https://github.com/algorand/algorand-sdk-testing"
3+
SDK_TESTING_BRANCH="master"
4+
SDK_TESTING_HARNESS="test-harness"
5+
6+
VERBOSE_HARNESS=0
7+
8+
# WARNING: If set to 1, new features will be LOST when downloading the test harness.
9+
# REGARDLESS: modified features are ALWAYS overwritten.
10+
REMOVE_LOCAL_FEATURES=0
11+
12+
# WARNING: Be careful when turning on the next variable.
13+
# In that case you'll need to provide all variables expected by `algorand-sdk-testing`'s `.env`
14+
OVERWRITE_TESTING_ENVIRONMENT=0

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,33 @@
11
# Changelog
22

3+
## What's Changed
4+
### Bugfixes
5+
* Bug-fix: Pass verbosity through to testing harness by @tzaffi in https://github.com/algorand/py-algorand-sdk/pull/373
6+
### Enhancements
7+
* Enhancement: Trim the indexer images and use the sandbox instead of custom dockers by @tzaffi in https://github.com/algorand/py-algorand-sdk/pull/367
8+
* Enhancement: Add State Proof support by @shiqizng in https://github.com/algorand/py-algorand-sdk/pull/370
9+
* Enhancement: Deprecating use of langspec by @ahangsu in https://github.com/algorand/py-algorand-sdk/pull/371
10+
11+
## New Contributors
12+
* @ahangsu made their first contribution in https://github.com/algorand/py-algorand-sdk/pull/371
13+
14+
**Full Changelog**: https://github.com/algorand/py-algorand-sdk/compare/v1.16.1...v1.17.0
15+
16+
# v1.17.0b1
17+
## What's Changed
18+
### Bugfixes
19+
* Bug-fix: Pass verbosity through to testing harness by @tzaffi in https://github.com/algorand/py-algorand-sdk/pull/373
20+
### Enhancements
21+
* Enhancement: Trim the indexer images and use the sandbox instead of custom dockers by @tzaffi in https://github.com/algorand/py-algorand-sdk/pull/367
22+
* Enhancement: Add State Proof support by @shiqizng in https://github.com/algorand/py-algorand-sdk/pull/370
23+
* Enhancement: Deprecating use of langspec by @ahangsu in https://github.com/algorand/py-algorand-sdk/pull/371
24+
25+
## New Contributors
26+
* @ahangsu made their first contribution in https://github.com/algorand/py-algorand-sdk/pull/371
27+
28+
**Full Changelog**: https://github.com/algorand/py-algorand-sdk/compare/v1.16.1...v1.17.0b1
29+
30+
331
# v1.16.1
432
### Bugfixes
533
* bug-fix: add check to desc so we dont output null if undefined by @barnjamin in https://github.com/algorand/py-algorand-sdk/pull/368

Dockerfile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,4 @@ RUN pip install . -q \
1111
&& pip install -r requirements.txt -q
1212

1313
# Run integration tests
14-
CMD ["/bin/bash", "-c", "make unit && make integration"]
15-
14+
CMD ["/bin/bash", "-c", "python --version && make unit && make integration"]

Makefile

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
UNITS = "@unit.abijson or @unit.abijson.byname or @unit.algod or @unit.algod.ledger_refactoring or @unit.applications or @unit.atc_method_args or @unit.atomic_transaction_composer or @unit.dryrun or @unit.dryrun.trace.application or @unit.feetest or @unit.indexer or @unit.indexer.ledger_refactoring or @unit.indexer.logs or @unit.offline or @unit.rekey or @unit.transactions.keyreg or @unit.responses or @unit.responses.231 or @unit.tealsign or @unit.transactions or @unit.transactions.payment or @unit.responses.unlimited_assets or @unit.sourcemap"
1+
UNIT_TAGS := "$(subst :, or ,$(shell awk '{print $2}' tests/unit.tags | paste -s -d: -))"
2+
INTEGRATION_TAGS := "$(subst :, or ,$(shell awk '{print $2}' tests/integration.tags | paste -s -d: -))"
3+
24
unit:
3-
behave --tags=$(UNITS) tests -f progress2
5+
behave --tags=$(UNIT_TAGS) tests -f progress2
46

5-
INTEGRATIONS = "@abi or @algod or @applications or @applications.verified or @assets or @auction or @c2c or @compile or @dryrun or @dryrun.testing or @indexer or @indexer.231 or @indexer.applications or @kmd or @rekey_v1 or @send.keyregtxn or @send or @compile.sourcemap"
67
integration:
7-
behave --tags=$(INTEGRATIONS) tests -f progress2
8+
behave --tags=$(INTEGRATION_TAGS) tests -f progress2 --no-capture
9+
10+
display-all-python-steps:
11+
find tests/steps -name "*.py" | xargs grep "behave" 2>/dev/null | cut -d: -f1 | sort | uniq | xargs awk "/@(given|step|then|when)/,/[)]/" | grep -E "(\".+\"|\'.+\')"
12+
13+
harness:
14+
./test-harness.sh
815

916
PYTHON_VERSION ?= 3.8
10-
docker-test:
11-
PYTHON_VERSION='$(PYTHON_VERSION)' ./run_integration.sh
17+
docker-pysdk-build:
18+
docker build -t py-sdk-testing --build-arg PYTHON_VERSION="${PYTHON_VERSION}" .
19+
20+
docker-pysdk-run:
21+
docker ps -a
22+
docker run -it --network host py-sdk-testing:latest
23+
24+
docker-test: harness docker-pysdk-build docker-pysdk-run

README.md

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,30 +14,37 @@ Run `$ pip3 install py-algorand-sdk` to install the package.
1414
Alternatively, choose a [distribution file](https://pypi.org/project/py-algorand-sdk/#files), and run `$ pip3 install [file name]`.
1515

1616
## Supported Python versions
17+
1718
py-algorand-sdk's minimum Python version policy attempts to balance several constraints.
19+
1820
* Make it easy for the community to use py-algorand-sdk by minimizing or excluding the need to customize Python installations.
1921
* Provide maintainers with access to newer language features that produce more robust software.
2022

2123
Given these constraints, the minimum Python version policy is:
2224
Target Python version on newest [Ubuntu LTS](https://wiki.ubuntu.com/Releases) released >= 6 months ago.
2325

2426
The rationale is:
27+
2528
* If a major Linux OS distribution bumps a Python version, then it's sufficiently available to the community for us to upgrade.
2629
* The 6 month time buffer ensures we delay upgrades until the community starts using a recently released LTS version.
2730

2831
## SDK Development
2932

3033
Install dependencies
3134

32-
- `pip3 install -r requirements.txt`
35+
* `pip3 install -r requirements.txt`
3336

3437
Run tests
3538

36-
- `make docker-test`
39+
* `make docker-test`
40+
41+
Set up the Algorand Sandbox based test-harness without running the tests
42+
43+
* `make harness`
3744

3845
Format code:
3946

40-
- `black .`
47+
* `black .`
4148

4249
## Quick start
4350

@@ -61,6 +68,7 @@ else:
6168
## Node setup
6269

6370
Follow the instructions in Algorand's [developer resources](https://developer.algorand.org/docs/run-a-node/setup/install/) to install a node on your computer.
71+
You can also set up a local [Algorand Sandbox](https://github.com/algorand/sandbox) with `make harness`.
6472

6573
## Running examples/example.py
6674

algosdk/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626
"""str: indicates an asset transfer transaction"""
2727
APPCALL_TXN = "appl"
2828
"""str: indicates an app call transaction, allows creating, deleting, and interacting with an application"""
29+
STATEPROOF_TXN = "stpf"
30+
"""str: indicates an state proof transaction"""
2931

3032
# note field types
3133
NOTE_FIELD_TYPE_DEPOSIT = "d"
@@ -134,3 +136,4 @@
134136
logic_sig_max_cost = LOGIC_SIG_MAX_COST
135137
logic_sig_max_size = LOGIC_SIG_MAX_SIZE
136138
app_page_max_size = APP_PAGE_MAX_SIZE
139+
stateproof_txn = STATEPROOF_TXN

algosdk/future/transaction.py

Lines changed: 128 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from typing import List, Union
22
import base64
3+
import binascii
34
from enum import IntEnum
45
import msgpack
56
from collections import OrderedDict
@@ -260,6 +261,11 @@ def undictify(d):
260261
elif txn_type == constants.appcall_txn:
261262
args.update(ApplicationCallTxn._undictify(d))
262263
txn = ApplicationCallTxn(**args)
264+
elif txn_type == constants.stateproof_txn:
265+
# a state proof txn does not have these fields
266+
args.pop("note"), args.pop("rekey_to"), args.pop("lease")
267+
args.update(StateProofTxn._undictify(d))
268+
txn = StateProofTxn(**args)
263269
if "grp" in d:
264270
txn.group = d["grp"]
265271
return txn
@@ -2505,13 +2511,54 @@ class LogicSig:
25052511
"""
25062512

25072513
def __init__(self, program, args=None):
2508-
if not program or not logic.check_program(program, args):
2509-
raise error.InvalidProgram()
2514+
self._sanity_check_program(program)
25102515
self.logic = program
25112516
self.args = args
25122517
self.sig = None
25132518
self.msig = None
25142519

2520+
@staticmethod
2521+
def _sanity_check_program(program):
2522+
"""
2523+
Performs heuristic program validation:
2524+
check if passed in bytes are Algorand address, or they are B64 encoded, rather than Teal bytes
2525+
2526+
Args:
2527+
program (bytes): compiled program
2528+
"""
2529+
2530+
def is_ascii_printable(program_bytes):
2531+
return all(
2532+
map(
2533+
lambda x: x == ord("\n") or (ord(" ") <= x <= ord("~")),
2534+
program_bytes,
2535+
)
2536+
)
2537+
2538+
if not program:
2539+
raise error.InvalidProgram("empty program")
2540+
2541+
if is_ascii_printable(program):
2542+
try:
2543+
encoding.decode_address(program.decode("utf-8"))
2544+
raise error.InvalidProgram(
2545+
"requesting program bytes, get Algorand address"
2546+
)
2547+
except error.WrongChecksumError:
2548+
pass
2549+
except error.WrongKeyLengthError:
2550+
pass
2551+
2552+
try:
2553+
base64.b64decode(program.decode("utf-8"))
2554+
raise error.InvalidProgram("program should not be b64 encoded")
2555+
except binascii.Error:
2556+
pass
2557+
2558+
raise error.InvalidProgram(
2559+
"program bytes are all ASCII printable characters, not looking like Teal byte code"
2560+
)
2561+
25152562
def dictify(self):
25162563
od = OrderedDict()
25172564
if self.args:
@@ -2548,7 +2595,7 @@ def verify(self, public_key):
25482595
return False
25492596

25502597
try:
2551-
logic.check_program(self.logic, self.args)
2598+
self._sanity_check_program(self.logic)
25522599
except error.InvalidProgram:
25532600
return False
25542601

@@ -2906,6 +2953,84 @@ def __eq__(self, other):
29062953
return False
29072954

29082955

2956+
class StateProofTxn(Transaction):
2957+
"""
2958+
Represents a state proof transaction
2959+
2960+
Arguments:
2961+
sender (str): address of the sender
2962+
state_proof (dict(), optional)
2963+
state_proof_message (dict(), optional)
2964+
state_proof_type (str, optional): state proof type
2965+
sp (SuggestedParams): suggested params from algod
2966+
2967+
2968+
Attributes:
2969+
sender (str)
2970+
sprf (dict())
2971+
sprfmsg (dict())
2972+
sprf_type (str)
2973+
first_valid_round (int)
2974+
last_valid_round (int)
2975+
genesis_id (str)
2976+
genesis_hash (str)
2977+
type (str)
2978+
"""
2979+
2980+
def __init__(
2981+
self,
2982+
sender,
2983+
sp,
2984+
state_proof=None,
2985+
state_proof_message=None,
2986+
state_proof_type=None,
2987+
):
2988+
Transaction.__init__(
2989+
self, sender, sp, None, None, constants.stateproof_txn, None
2990+
)
2991+
2992+
self.sprf_type = state_proof_type
2993+
self.sprf = state_proof
2994+
self.sprfmsg = state_proof_message
2995+
2996+
def dictify(self):
2997+
d = dict()
2998+
if self.sprf_type:
2999+
d["sptype"] = self.sprf_type
3000+
if self.sprfmsg:
3001+
d["spmsg"] = self.sprfmsg
3002+
if self.sprf:
3003+
d["sp"] = self.sprf
3004+
d.update(super(StateProofTxn, self).dictify())
3005+
od = OrderedDict(sorted(d.items()))
3006+
3007+
return od
3008+
3009+
@staticmethod
3010+
def _undictify(d):
3011+
args = {}
3012+
if "sptype" in d:
3013+
args["state_proof_type"] = d["sptype"]
3014+
if "sp" in d:
3015+
args["state_proof"] = d["sp"]
3016+
if "spmsg" in d:
3017+
args["state_proof_message"] = d["spmsg"]
3018+
3019+
return args
3020+
3021+
def __eq__(self, other):
3022+
if not isinstance(other, StateProofTxn):
3023+
return False
3024+
return (
3025+
super(StateProofTxn, self).__eq__(other)
3026+
and self.sprf_type == other.sprf_type
3027+
and self.sprf == other.sprf
3028+
and self.sprfmsg == other.sprfmsg
3029+
)
3030+
3031+
return False
3032+
3033+
29093034
def write_to_file(txns, path, overwrite=True):
29103035
"""
29113036
Write signed or unsigned transactions to a file.

0 commit comments

Comments
 (0)