Skip to content

Commit

Permalink
Merge branch 'release/v2.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
algobarb committed May 8, 2023
2 parents bd5d041 + 44e6f6f commit c7639ca
Show file tree
Hide file tree
Showing 62 changed files with 722 additions and 975 deletions.
4 changes: 3 additions & 1 deletion .github/workflows/pr-type-category.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@ jobs:
labels: "New Feature, Enhancement, Bug-Fix, Not-Yet-Enabled, Skip-Release-Notes"

- name: "Checking for PR Category in PR title. Should be like '<category>: <pr title>'."
env:
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
if [[ ! "${{ github.event.pull_request.title }}" =~ ^.{2,}\:.{2,} ]]; then
if [[ ! "$PR_TITLE" =~ ^.{2,}\:.{2,} ]]; then
echo "## PR Category is missing from PR title. Please add it like '<category>: <pr title>'." >> GITHUB_STEP_SUMMARY
exit 1
fi
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

# v2.2.0

## What's Changed
Supports new devmode block timestamp offset endpoints.
### Bugfixes
* Fix: improve SignedTransaction type signature for dryrun and send_transaction by @barnjamin in https://github.com/algorand/py-algorand-sdk/pull/457
* Fix: add auth addr for multisig sign when the msig has been rekeyed by @barnjamin in https://github.com/algorand/py-algorand-sdk/pull/460
### New Features
* Simulation: Lift log limits option in SimulateRequest by @ahangsu in https://github.com/algorand/py-algorand-sdk/pull/469
### Enhancements
* Docs: Examples by @barnjamin in https://github.com/algorand/py-algorand-sdk/pull/454
* BugFix: ATC error message improvement by @barnjamin in https://github.com/algorand/py-algorand-sdk/pull/463
* API: Support updated simulate endpoint by @jasonpaulos in https://github.com/algorand/py-algorand-sdk/pull/466
* algod: Add endpoints for devmode timestamps, sync, and ready by @algochoi in https://github.com/algorand/py-algorand-sdk/pull/468
* DevOps: Add CODEOWNERS to restrict workflow editing by @onetechnical in https://github.com/algorand/py-algorand-sdk/pull/473


**Full Changelog**: https://github.com/algorand/py-algorand-sdk/compare/v2.1.2...v2.2.0

# v2.1.2

## What's Changed
Expand Down
2 changes: 2 additions & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.github/ @algorand/dev
.circleci/ @algorand/dev
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ RUN pip install . -q \
&& pip install -r requirements.txt -q

# Run integration tests
CMD ["/bin/bash", "-c", "python --version && make unit && make integration"]
CMD ["/bin/bash", "-c", "python --version && make unit && make integration && make smoke-test-examples"]
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,9 @@ docker-pysdk-run:
docker ps -a
docker run -it --network host py-sdk-testing:latest

# todo replace with ports from harness .env file
smoke-test-examples:
cd examples && bash smoke_test.sh && cd -


docker-test: harness docker-pysdk-build docker-pysdk-run
55 changes: 0 additions & 55 deletions _examples/indexer.py

This file was deleted.

92 changes: 0 additions & 92 deletions _examples/utils.py

This file was deleted.

80 changes: 65 additions & 15 deletions algosdk/atomic_transaction_composer.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
from algosdk import abi, error, transaction
from algosdk.transaction import GenericSignedTransaction
from algosdk.abi.address_type import AddressType
from algosdk.v2client import algod
from algosdk.v2client import algod, models


# The first four bytes of an ABI method call return must have this hash
ABI_RETURN_HASH = b"\x15\x1f\x7c\x75"
Expand Down Expand Up @@ -255,35 +256,67 @@ def __init__(
decode_error: Optional[Exception],
tx_info: dict,
method: abi.Method,
missing_signature: bool,
) -> None:
self.tx_id = tx_id
self.raw_value = raw_value
self.return_value = return_value
self.decode_error = decode_error
self.tx_info = tx_info
self.method = method
self.missing_signature = missing_signature


class SimulateEvalOverrides:
def __init__(
self,
*,
max_log_calls: Optional[int] = None,
max_log_size: Optional[int] = None,
allow_empty_signatures: Optional[bool] = None,
) -> None:
self.max_log_calls = max_log_calls
self.max_log_size = max_log_size
self.allow_empty_signatures = allow_empty_signatures

@staticmethod
def from_simulation_result(
simulation_result: Dict[str, Any]
) -> Optional["SimulateEvalOverrides"]:
if "eval-overrides" not in simulation_result:
return None

eval_override_dict = simulation_result.get("eval-overrides", dict())
eval_override = SimulateEvalOverrides()

if "max-log-calls" in eval_override_dict:
eval_override.max_log_calls = eval_override_dict["max-log-calls"]
if "max-log-size" in eval_override_dict:
eval_override.max_log_size = eval_override_dict["max-log-size"]
if "allow-empty-signatures" in eval_override_dict:
eval_override.allow_empty_signatures = eval_override_dict[
"allow-empty-signatures"
]

return eval_override


class SimulateAtomicTransactionResponse:
def __init__(
self,
version: int,
would_succeed: bool,
failure_message: str,
failed_at: Optional[List[int]],
simulate_response: Dict[str, Any],
tx_ids: List[str],
results: List[SimulateABIResult],
eval_overrides: Optional[SimulateEvalOverrides] = None,
) -> None:
self.version = version
self.would_succeed = would_succeed
self.failure_message = failure_message
self.failed_at = failed_at
self.simulate_response = simulate_response
self.tx_ids = tx_ids
self.abi_results = results
self.eval_overrides = eval_overrides


class AtomicTransactionComposer:
Expand Down Expand Up @@ -495,15 +528,18 @@ def add_method_call(
# or encode a ABI value.
for i, arg in enumerate(method.args):
if abi.is_abi_transaction_type(arg.type):
if not isinstance(
method_args[i], TransactionWithSigner
) or not abi.check_abi_transaction_type(
if not isinstance(method_args[i], TransactionWithSigner):
raise error.AtomicTransactionComposerError(
"expected TransactionWithSigner as method argument, "
f"but received: {method_args[i]}"
)

if not abi.check_abi_transaction_type(
arg.type, method_args[i].txn
):
raise error.AtomicTransactionComposerError(
"expected TransactionWithSigner as method argument, but received: {}".format(
method_args[i]
)
f"expected Transaction type {arg.type} as method argument, "
f"but received: {method_args[i].txn.type}"
)
txn_list.append(method_args[i])
else:
Expand Down Expand Up @@ -683,7 +719,9 @@ def submit(self, client: algod.AlgodClient) -> List[str]:
return self.tx_ids

def simulate(
self, client: algod.AlgodClient
self,
client: algod.AlgodClient,
request: Optional[models.SimulateRequest] = None,
) -> SimulateAtomicTransactionResponse:
"""
Send the transaction group to the `simulate` endpoint and wait for results.
Expand All @@ -693,6 +731,8 @@ def simulate(
Args:
client (AlgodClient): Algod V2 client
request (models.SimulateRequest): SimulateRequest with options in simulation.
The request's transaction group will be overrwritten by the composer's group, only simulation related options will be used.
Returns:
SimulateAtomicTransactionResponse: Object with simulation results for this
Expand All @@ -710,9 +750,18 @@ def simulate(
"lower to simulate a group"
)

current_simulation_request = (
request if request else models.SimulateRequest(txn_groups=list())
)
current_simulation_request.txn_groups = [
models.SimulateRequestTransactionGroup(txns=self.signed_txns)
]

simulation_result = cast(
Dict[str, Any], client.simulate_transactions(self.signed_txns)
Dict[str, Any],
client.simulate_transactions(current_simulation_request),
)

# Only take the first group in the simulate response
txn_group: Dict[str, Any] = simulation_result["txn-groups"][0]

Expand Down Expand Up @@ -751,18 +800,19 @@ def simulate(
decode_error=result.decode_error,
tx_info=result.tx_info,
method=result.method,
missing_signature=sim_txn.get("missing-signature", False),
)
)

return SimulateAtomicTransactionResponse(
version=simulation_result.get("version", 0),
would_succeed=simulation_result.get("would-succeed", False),
failure_message=txn_group.get("failure-message", ""),
failed_at=txn_group.get("failed-at"),
simulate_response=simulation_result,
tx_ids=self.tx_ids,
results=sim_results,
eval_overrides=SimulateEvalOverrides.from_simulation_result(
simulation_result
),
)

def execute(
Expand Down
2 changes: 1 addition & 1 deletion algosdk/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
"""str: header key for algod requests"""
INDEXER_AUTH_HEADER = "X-Indexer-API-Token"
"""str: header key for indexer requests"""
UNVERSIONED_PATHS = ["/health", "/versions", "/metrics", "/genesis"]
UNVERSIONED_PATHS = ["/health", "/versions", "/metrics", "/genesis", "/ready"]
"""str[]: paths that don't use the version path prefix"""
NO_AUTH: List[str] = []
"""str[]: requests that don't require authentication"""
Expand Down
5 changes: 5 additions & 0 deletions algosdk/kmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,11 @@ def sign_multisig_transaction(self, handle, password, public_key, mtx):
"public_key": public_key,
"partial_multisig": partial,
}

if hasattr(mtx, "auth_addr") and mtx.auth_addr is not None:
signer = base64.b64encode(encoding.decode_address(mtx.auth_addr))
query["signer"] = signer.decode()

result = self.kmd_request("POST", req, data=query)["multisig"]
msig = encoding.msgpack_decode(result)
mtx.multisig = msig
Expand Down
Loading

0 comments on commit c7639ca

Please sign in to comment.