Skip to content

Commit

Permalink
Add GetTransactionSigners neo-project/neo#2685
Browse files Browse the repository at this point in the history
  • Loading branch information
ixje committed Apr 19, 2022
1 parent d79adb3 commit f825a60
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 7 deletions.
8 changes: 8 additions & 0 deletions neo3/contracts/native/ledger.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,14 @@ def get_tx_for_contract(self, snapshot: storage.Snapshot, hash_: types.UInt256)
return None
return tx

@register("getTransactionSigners", contracts.CallFlags.READ_STATES, cpu_price=1 << 15)
def get_tx_signers(self, snapshot: storage.Snapshot, hash_: types.UInt256) -> Optional[payloads.Signer]:
tx = snapshot.transactions.try_get(hash_)
if tx is None:
return None
else:
return tx.signers

@register("getTransactionVMState", contracts.CallFlags.READ_STATES, cpu_price=1 << 15)
def get_tx_vmstate(self, snapshot: storage.Snapshot, hash_: types.UInt256) -> vm.VMState:
tx = snapshot.transactions.try_get(hash_, read_only=True)
Expand Down
81 changes: 75 additions & 6 deletions neo3/network/payloads/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
import abc
import base64
from enum import IntFlag, IntEnum
from neo3.core import serialization, utils, types, cryptography, Size as s, IJson
from neo3.core import serialization, utils, types, cryptography, Size as s, IJson, IInteroperable
from neo3.network import payloads
from neo3 import storage, contracts
from typing import List, Dict, Any, no_type_check, Iterator
from neo3 import storage, contracts, vm
from typing import List, Dict, Any, no_type_check, Iterator, cast


class Signer(serialization.ISerializable, IJson):
class Signer(serialization.ISerializable, IJson, IInteroperable):
"""
A class that specifies who can pass CheckWitness() verifications in a smart contract.
"""
Expand Down Expand Up @@ -137,6 +137,26 @@ def to_json(self) -> dict:

return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
items: List[vm.StackItem] = []
items.append(vm.ByteStringStackItem(self.to_array()))
items.append(vm.ByteStringStackItem(self.account.to_array()))
items.append(vm.IntegerStackItem(self.scope.value))

contracts_ = vm.ArrayStackItem(reference_counter,
list(map(lambda c: vm.ByteStringStackItem(c.to_array()), self.allowed_contracts))
)
items.append(contracts_)

groups_ = vm.ArrayStackItem(reference_counter,
list(map(lambda g: vm.ByteStringStackItem(g.to_array()), self.allowed_groups)))
items.append(groups_)

rules_ = vm.ArrayStackItem(reference_counter,
list(map(lambda r: r.to_stack_item(reference_counter), self.rules)))
items.append(rules_)
return vm.ArrayStackItem(reference_counter, items)

@classmethod
def from_json(cls, json: dict):
""" Create object from JSON """
Expand Down Expand Up @@ -306,7 +326,7 @@ def to_csharp_string(self) -> str:
return self.name.title()


class WitnessCondition(serialization.ISerializable, IJson):
class WitnessCondition(serialization.ISerializable, IJson, IInteroperable):
MAX_SUB_ITEMS = 16
MAX_NESTING_DEPTH = 2

Expand Down Expand Up @@ -364,6 +384,11 @@ def to_json(self) -> dict:
def from_json(cls, json: dict):
raise NotImplementedError()

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
arr = vm.ArrayStackItem(reference_counter)
arr.append(vm.IntegerStackItem(self.type.value))
return arr


class ConditionAnd(WitnessCondition):
_type = WitnessConditionType.AND
Expand Down Expand Up @@ -397,6 +422,14 @@ def to_json(self) -> dict:
json['expressions'] = list(map(lambda exp: exp.to_json(), self.expressions))
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionAnd, self).to_stack_item(reference_counter)
expressions = list(map(lambda exp: exp.to_stack_item(reference_counter), self.expressions))
array = vm.ArrayStackItem(reference_counter, expressions)
base = cast(vm.ArrayStackItem, base)
base.append(array)
return base

@classmethod
def _serializable_init(cls):
return cls([])
Expand Down Expand Up @@ -430,6 +463,12 @@ def to_json(self) -> dict:
json['expression'] = self.value
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionBool, self).to_stack_item(reference_counter)
base = cast(vm.ArrayStackItem, base)
base.append(vm.BooleanStackItem(self.value))
return base

@classmethod
def _serializable_init(cls):
return cls(False)
Expand Down Expand Up @@ -465,6 +504,12 @@ def to_json(self) -> dict:
json["expression"] = self.expression.to_json()
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionNot, self).to_stack_item(reference_counter)
base = cast(vm.ArrayStackItem, base)
base.append(self.expression.to_stack_item(reference_counter))
return base

@classmethod
def _serializable_init(cls):
return cls(ConditionBool(False))
Expand Down Expand Up @@ -502,6 +547,14 @@ def to_json(self) -> dict:
json['expressions'] = list(map(lambda exp: exp.to_json(), self.expressions))
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionOr, self).to_stack_item(reference_counter)
expressions = list(map(lambda exp: exp.to_stack_item(reference_counter), self.expressions))
array = vm.ArrayStackItem(reference_counter, expressions)
base = cast(vm.ArrayStackItem, base)
base.append(array)
return base

@classmethod
def _serializable_init(cls):
return cls([])
Expand Down Expand Up @@ -530,6 +583,12 @@ def to_json(self) -> dict:
json["hash"] = f"0x{self.hash_}"
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionCalledByContract, self).to_stack_item(reference_counter)
base = cast(vm.ArrayStackItem, base)
base.append(vm.ByteStringStackItem(self.hash_.to_array()))
return base

@classmethod
def _serializable_init(cls):
return cls(types.UInt160.zero())
Expand Down Expand Up @@ -585,6 +644,12 @@ def to_json(self) -> dict:
json["group"] = str(self.group)
return json

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
base = super(ConditionCalledByGroup, self).to_stack_item(reference_counter)
base = cast(vm.ArrayStackItem, base)
base.append(vm.ByteStringStackItem(self.group.to_array()))
return base

@classmethod
def _serializable_init(cls):
return cls(cryptography.ECPoint.deserialize_from_bytes(b'\x00'))
Expand All @@ -606,7 +671,7 @@ def match(self, engine: contracts.ApplicationEngine) -> bool:
return engine.current_scripthash == self.hash_


class WitnessRule(serialization.ISerializable, IJson):
class WitnessRule(serialization.ISerializable, IJson, IInteroperable):
def __init__(self, action: WitnessRuleAction, condition: WitnessCondition):
self.action = action
self.condition = condition
Expand All @@ -628,6 +693,10 @@ def to_json(self) -> dict:
'condition': self.condition.to_json()
}

def to_stack_item(self, reference_counter: vm.ReferenceCounter) -> vm.StackItem:
return vm.ArrayStackItem(reference_counter, [vm.IntegerStackItem(self.action.value),
self.condition.to_stack_item(reference_counter)])

@classmethod
def from_json(cls, json: dict):
raise NotImplementedError()
Expand Down
2 changes: 1 addition & 1 deletion neo3/network/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def __init__(self, *args, **kwargs):

def connection_made(self, transport: asyncio.transports.BaseTransport) -> None:
super().connection_made(transport)
self._stream_writer = StreamWriter(transport, self, self._stream_reader_orig, self._loop)
self._stream_writer = StreamWriter(transport, self, self._stream_reader_orig, self._loop) # type: ignore

if self.client:
asyncio.create_task(self.client.connection_made(transport))
Expand Down
1 change: 1 addition & 0 deletions tests/network/test_payloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ def setUpClass(cls) -> None:
ECPoint p = ECPoint.Parse("026241e7e26b38bb7154b8ad49458b97fb1c4797443dc921c5ca5774f511a2bbfc", ECCurve.Secp256r1);
co.AllowedGroups = new ECPoint[] { p };
co.Rules = new WitnessRule[0];
Console.WriteLine($"{co.Size}");
Console.WriteLine($"{BitConverter.ToString(co.ToArray()).Replace("-","")}");
Expand Down
10 changes: 10 additions & 0 deletions tests/network/test_witnessrules.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from neo3.network import payloads
from neo3.core import types, cryptography


class WitnessRuleTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
Expand Down Expand Up @@ -222,6 +223,15 @@ def test_by_entry(self):
self.assertEqual(c, deserialized_c)

def test_called_by_group(self):
"""
var c = new CalledByGroupCondition()
{
Group = ECPoint.Parse("02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765", ECCurve.Secp256r1)
};
Console.WriteLine(((ISerializable)c).Size);
Console.WriteLine(c.ToArray().ToHexString());
Console.WriteLine(c.ToJson());
"""
expected_len = 34
expected_data = bytes.fromhex("2902158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765")
expected_json = {"type":"CalledByGroup","group":"02158c4a4810fa2a6a12f7d33d835680429e1a68ae61161c5b3fbc98c7f1f17765"}
Expand Down

0 comments on commit f825a60

Please sign in to comment.