├── boa ├── code │ ├── __init__.py │ ├── action.py │ ├── appcall.py │ └── ast_preprocess.py ├── interop │ ├── __init__.py │ ├── System │ │ ├── __init__.py │ │ └── ExecutionEngine.py │ ├── Neo │ │ ├── Action.py │ │ ├── Validator.py │ │ ├── Witness.py │ │ ├── App.py │ │ ├── InvocationTransaction.py │ │ ├── TriggerType.py │ │ ├── Enumerator.py │ │ ├── Input.py │ │ ├── Attribute.py │ │ ├── TransactionType.py │ │ ├── Storage.py │ │ ├── Iterator.py │ │ ├── Runtime.py │ │ ├── Output.py │ │ ├── Account.py │ │ ├── Blockchain.py │ │ ├── __init__.py │ │ ├── Contract.py │ │ ├── Transaction.py │ │ ├── Header.py │ │ ├── Asset.py │ │ └── Block.py │ ├── SmartContract.py │ └── BigInteger.py ├── __init__.py ├── cli.py ├── abi.py ├── util.py └── builtins.py ├── boa_test ├── __init__.py ├── example │ ├── __init__.py │ ├── demo │ │ ├── __init__.py │ │ ├── token │ │ │ ├── __init__.py │ │ │ └── txio.py │ │ ├── AnotherModule.py │ │ ├── Demo2.py │ │ ├── SerializationTest.py │ │ ├── Demo1.py │ │ ├── IteratorTest.py │ │ ├── EnumeratorTest.py │ │ └── ICO_Template.py │ ├── blockchain │ │ ├── __init__.py │ │ ├── AppCallTest.py │ │ ├── AppCallTest2.py │ │ ├── DynamicAppCallTest.py │ │ ├── AppCallTest3.py │ │ ├── EventTest.py │ │ ├── ExecutionEngineTest.py │ │ ├── RuntimeTest.py │ │ ├── StorageTest.py │ │ ├── TriggerTypeTest.py │ │ ├── ContractTest.py │ │ ├── OutputsTest.py │ │ ├── AccountTest.py │ │ ├── StorageFindTest.py │ │ ├── SignatureTest.py │ │ ├── BlockTest.py │ │ ├── TransactionTypeTest.py │ │ └── TransactionTest.py │ ├── .gitignore │ ├── AddTestVoid.py │ ├── AddTest.py │ ├── AddTest4.py │ ├── ModuleVariableTest1.py │ ├── AddTest2.py │ ├── DictTest1.py │ ├── CompareTest0.py │ ├── DictTest2.py │ ├── RangeTest.py │ ├── CompareTest2.py │ ├── WhileTest1.py │ ├── AddTest3.py │ ├── ThrowTest.py │ ├── DictTest3.py │ ├── ThrowIfNotTest.py │ ├── ArrayRemoveTest.py │ ├── IterTest.py │ ├── WhileTest2.py │ ├── AddTest1.py │ ├── ModuleMethodTest2.py │ ├── ArrayReverseTest.py │ ├── IterTest2.py │ ├── IterTest7.py │ ├── TakeTest.py │ ├── DictTest6_ShouldNotCompile.py │ ├── IterTest6.py │ ├── ArrayTest.py │ ├── MethodTest.py │ ├── AbiMethods8.py │ ├── ModuleMethodTest1.py │ ├── ByteArrayTest3.py │ ├── CompareTest3.py │ ├── DictTest5_ShouldNotCompile.py │ ├── ConcatTest.py │ ├── IterTest8.py │ ├── ArrayTest4.py │ ├── MethodTest4.py │ ├── AbiMethods6.py │ ├── ByteArrayTest.py │ ├── AbiMethods3.py │ ├── AbiMethods7.py │ ├── AbiMethods2.py │ ├── ArrayTest3.py │ ├── AbiMethods5.py │ ├── MethodTest5.py │ ├── SliceTest.py │ ├── AppendTest.py │ ├── WhileTest.py │ ├── AbiMethods1.py │ ├── AbiMethods4.py │ ├── Fibonacci.py │ ├── ModuleVariableTest.py │ ├── DictTest4.py │ ├── ConcatTest2.py │ ├── IterTest4.py │ ├── ByteArrayTest2.py │ ├── IterTest3.py │ ├── IterTest5.py │ ├── ArrayTest1.py │ ├── DictTestHasKey.py │ ├── NoneTest.py │ ├── ArrayTest2.py │ ├── CompareTest1.py │ ├── DictTestValues.py │ ├── MethodTest3.py │ ├── OpCallTest.py │ ├── EqualityTest.py │ ├── BinopTest.py │ ├── DictTestKeys.py │ ├── ArrayArgsTest.py │ ├── NotEqualTest.py │ ├── EqualityTest2.py │ ├── MethodTest2.py │ ├── SliceTest2.py │ ├── BreakpointTest.py │ ├── VerifySignatureTest.py │ ├── TestManyElif.py │ └── CompareInTest.py └── tests │ ├── __init__.py │ ├── test_demo.py │ ├── test_verify_signature.py │ ├── test_slice.py │ ├── test_compiler.py │ ├── test_many_elif.py │ ├── test_throw.py │ ├── test_bytearray.py │ ├── test_dict.py │ ├── test_system.py │ ├── test_event.py │ ├── test_module_vars.py │ ├── test_equality.py │ ├── test_account.py │ ├── test_compare_in.py │ ├── test_dict_create.py │ ├── test_storage_find.py │ ├── test_serialization.py │ ├── test_addtest.py │ ├── test_opcalls.py │ ├── test_methodtest.py │ ├── test_enumerators.py │ ├── test_conditional.py │ ├── test_methodtest_nonnep8.py │ ├── test_block.py │ ├── test_concat.py │ ├── test_storage.py │ ├── test_runtime.py │ ├── test_binops.py │ └── test_lists.py ├── requirements.txt ├── fixtures ├── coztest.db3 ├── testwallet.db3 ├── testwallet2.db3 ├── testwallet3.db3 ├── neo-test1-w.wallet ├── neo-test2-w.wallet ├── neo-test3-w.wallet ├── empty_fixture.tar.gz ├── neo-test-coz.wallet ├── neo-test1-bc.wallet ├── neo-test2-bc.wallet └── .gitignore ├── .coveragerc ├── requirements_test.txt ├── docs ├── source │ ├── tests.rst │ ├── boa │ │ ├── compiler.rst │ │ ├── code │ │ │ ├── method.rst │ │ │ ├── module.rst │ │ │ ├── pytoken.rst │ │ │ ├── vmtoken.rst │ │ │ └── expression.rst │ │ └── interop │ │ │ ├── executionengine.rst │ │ │ └── blockchain.rst │ ├── license.rst │ ├── basicusage.rst │ ├── contribute.rst │ ├── install.rst │ ├── example │ │ └── index.rst │ └── index.rst └── Makefile ├── .gitignore ├── docker ├── Dockerfile └── compiler.py ├── setup.cfg ├── requirements_dev.txt ├── .github ├── PULL_REQUEST_TEMPLATE.md └── CODE_OF_CONDUCT.md ├── .travis.yml ├── Makefile ├── LICENSE.md ├── .circleci └── config.yml ├── CHANGELOG.rst ├── README.rst └── setup.py /boa/code/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa/interop/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/example/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa/interop/System/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/example/demo/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa/__init__.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.7.2' 2 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/example/demo/token/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /boa_test/example/.gitignore: -------------------------------------------------------------------------------- 1 | !.gitignore 2 | 3 | *.avm 4 | *.json 5 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | astor>=0.6.2 2 | logzero==1.5.0 3 | bytecode==0.10.0 4 | -------------------------------------------------------------------------------- /boa_test/example/AddTestVoid.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(m): 5 | 6 | c = m + 2 7 | -------------------------------------------------------------------------------- /fixtures/coztest.db3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/coztest.db3 -------------------------------------------------------------------------------- /fixtures/testwallet.db3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/testwallet.db3 -------------------------------------------------------------------------------- /fixtures/testwallet2.db3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/testwallet2.db3 -------------------------------------------------------------------------------- /fixtures/testwallet3.db3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/testwallet3.db3 -------------------------------------------------------------------------------- /fixtures/neo-test1-w.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test1-w.wallet -------------------------------------------------------------------------------- /fixtures/neo-test2-w.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test2-w.wallet -------------------------------------------------------------------------------- /fixtures/neo-test3-w.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test3-w.wallet -------------------------------------------------------------------------------- /boa_test/example/AddTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(m): 5 | 6 | c = m + 2 7 | 8 | return c 9 | -------------------------------------------------------------------------------- /boa_test/example/AddTest4.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(a, b, c, d): 5 | 6 | return a + b - c * d 7 | -------------------------------------------------------------------------------- /fixtures/empty_fixture.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/empty_fixture.tar.gz -------------------------------------------------------------------------------- /fixtures/neo-test-coz.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test-coz.wallet -------------------------------------------------------------------------------- /fixtures/neo-test1-bc.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test1-bc.wallet -------------------------------------------------------------------------------- /fixtures/neo-test2-bc.wallet: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CityOfZion/neo-boa/HEAD/fixtures/neo-test2-bc.wallet -------------------------------------------------------------------------------- /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | source = boa 3 | 4 | [report] 5 | omit = 6 | venv* 7 | boa_test/* 8 | boa/interop/* 9 | boa/builtins.py -------------------------------------------------------------------------------- /fixtures/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !empty_fixture.tar.gz 3 | !coztest.db3 4 | !testwallet.db3 5 | !testwallet2.db3 6 | !testwallet3.db3 7 | !neo-test* -------------------------------------------------------------------------------- /boa_test/example/ModuleVariableTest1.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | WHAT = 5 4 | 5 | 6 | def Main(): 7 | 8 | m = 3 + WHAT 9 | 10 | return m 11 | -------------------------------------------------------------------------------- /boa_test/example/AddTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | a = 1 7 | b = 2 8 | c = a + b 9 | 10 | return c 11 | -------------------------------------------------------------------------------- /boa_test/example/DictTest1.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | 5 | d = {} 6 | 7 | d['a'] = 4 8 | d[13] = 3 9 | 10 | return d 11 | -------------------------------------------------------------------------------- /boa_test/example/CompareTest0.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(a, b): 5 | 6 | if a > b: 7 | 8 | return 3 9 | 10 | return 2 11 | -------------------------------------------------------------------------------- /requirements_test.txt: -------------------------------------------------------------------------------- 1 | logzero==1.5.0 2 | astor>=0.6.2 3 | git+https://github.com/CityOfZion/neo-python.git@development#egg=neo-python 4 | coz-bytecode==0.5.1 -------------------------------------------------------------------------------- /boa_test/example/DictTest2.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | 5 | d = {} 6 | 7 | d['a'] = 4 8 | d[13] = 3 9 | 10 | return d['a'] + d[13] 11 | -------------------------------------------------------------------------------- /boa_test/example/RangeTest.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import range 3 | 4 | 5 | def Main(): 6 | 7 | a = range(100, 120) 8 | 9 | return a 10 | -------------------------------------------------------------------------------- /boa_test/example/CompareTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(a, b): 5 | 6 | if a == b: 7 | 8 | return True 9 | 10 | return False 11 | -------------------------------------------------------------------------------- /boa_test/example/WhileTest1.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | j = 3 7 | while j < 6: 8 | j = j + 1 9 | 10 | return j 11 | -------------------------------------------------------------------------------- /boa_test/example/AddTest3.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(): 3 | 4 | a = 1 5 | b = 2 6 | c = 3 7 | e = 4 8 | d = a + b - c * e 9 | 10 | return d 11 | -------------------------------------------------------------------------------- /boa_test/example/ThrowTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(j): 5 | 6 | if j == 4: 7 | 8 | raise Exception('hello') 9 | 10 | return True 11 | -------------------------------------------------------------------------------- /boa/interop/Neo/Action.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def RegisterAction(event_name, *args): 4 | """ 5 | 6 | :param event_name: 7 | :param args: 8 | """ 9 | pass 10 | -------------------------------------------------------------------------------- /docs/source/tests.rst: -------------------------------------------------------------------------------- 1 | Tests 2 | ----- 3 | 4 | All tests are located in ``boa_test/test``. Tests can be run with the following command ``python -m unittest discover boa_test`` -------------------------------------------------------------------------------- /boa/interop/Neo/Validator.py: -------------------------------------------------------------------------------- 1 | 2 | class Validator: 3 | pass 4 | 5 | 6 | def Register(pubkey): 7 | """ 8 | 9 | :param pubkey: 10 | """ 11 | pass 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | venv/ 3 | __pycache__ 4 | .avm 5 | *.avmdbgnfo 6 | *.abi.json 7 | dist 8 | build 9 | neo_boa.egg-info 10 | *.egg-info 11 | /build 12 | vm_instructions.log 13 | -------------------------------------------------------------------------------- /boa_test/example/DictTest3.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | 5 | d = {} 6 | 7 | d['a'] = 4 8 | d[13] = 3 9 | 10 | d['mydict'] = {} 11 | 12 | return d['mydict'] 13 | -------------------------------------------------------------------------------- /boa_test/example/ThrowIfNotTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import throw_if_null 4 | 5 | 6 | def Main(x1): 7 | 8 | throw_if_null(x1) 9 | 10 | return True 11 | -------------------------------------------------------------------------------- /boa_test/example/ArrayRemoveTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | """ 6 | 7 | :return: 8 | """ 9 | m = [16, 2, 3, 4] 10 | 11 | m.remove(1) 12 | 13 | return m 14 | -------------------------------------------------------------------------------- /boa_test/example/IterTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | items = [1, 2, 4, 8] 7 | 8 | j = 3 9 | 10 | for i in items: 11 | j += i 12 | 13 | return j 14 | -------------------------------------------------------------------------------- /docs/source/boa/compiler.rst: -------------------------------------------------------------------------------- 1 | boa.compiler.Compiler 2 | ===================== 3 | 4 | What follows are the details of the ``Compiler`` implementation. 5 | 6 | .. autoclass:: boa.compiler.Compiler 7 | :members: -------------------------------------------------------------------------------- /boa_test/example/WhileTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | j = 3 7 | while j < 8: 8 | j = j + 1 9 | 10 | if j == 6: 11 | break 12 | 13 | return j 14 | -------------------------------------------------------------------------------- /boa_test/example/AddTest1.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(a, b, c, d): 5 | a2 = a * 2 6 | 7 | b2 = b + 1 8 | 9 | c2 = c / 2 10 | 11 | d2 = d - 1 12 | 13 | return a2 + b2 + c2 + d2 14 | -------------------------------------------------------------------------------- /boa_test/example/ModuleMethodTest2.py: -------------------------------------------------------------------------------- 1 | 2 | BLAH = 10 * 300 3 | 4 | # This wont work 5 | # BLAH2 = BLAH * 100 6 | 7 | 8 | def Main(): 9 | 10 | m = 3 11 | 12 | j = m + BLAH 13 | 14 | return j 15 | -------------------------------------------------------------------------------- /boa_test/example/ArrayReverseTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | m = [1, 2, 4, 'blah'] 7 | 8 | m.reverse() 9 | 10 | # Notify(m) 11 | 12 | # m.reverse() 13 | 14 | return m[0] 15 | -------------------------------------------------------------------------------- /boa_test/example/IterTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | items = ['a', 'b', 'c', 1, 5] 7 | 8 | count = 3 9 | for i in items: 10 | 11 | count += 1 12 | 13 | return count 14 | -------------------------------------------------------------------------------- /boa_test/example/IterTest7.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import range 4 | 5 | 6 | def Main(): 7 | 8 | count = 0 9 | 10 | for i in range(0, 12): 11 | count += 1 12 | 13 | return count 14 | -------------------------------------------------------------------------------- /boa_test/example/TakeTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import take 4 | 5 | 6 | def Main(amount): 7 | 8 | str1 = 'helloworld1234567' 9 | 10 | str2 = take(str1, amount) 11 | 12 | return str2 13 | -------------------------------------------------------------------------------- /docs/source/license.rst: -------------------------------------------------------------------------------- 1 | License 2 | ------- 3 | 4 | - Open-source `MIT`_. 5 | - Main author is **localhuman** [ https://github.com/localhuman ]. 6 | 7 | .. _MIT: https://github.com/CityOfZion/neo-python/blob/master/LICENSE.md 8 | -------------------------------------------------------------------------------- /boa_test/example/DictTest6_ShouldNotCompile.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | # this file should/does not compile 7 | 8 | q = 3 9 | 10 | return {'a': 1, 'b': 2} # dictionaries must be declared before use 11 | -------------------------------------------------------------------------------- /boa_test/example/demo/AnotherModule.py: -------------------------------------------------------------------------------- 1 | from boa.builtins import breakpoint 2 | 3 | 4 | def another_module_method(m): 5 | 6 | thing = m * 2 7 | 8 | thing2 = thing + 32 9 | 10 | breakpoint() 11 | 12 | return thing2 13 | -------------------------------------------------------------------------------- /docs/source/boa/code/method.rst: -------------------------------------------------------------------------------- 1 | boa.code.method.Method 2 | ====================== 3 | 4 | What follows are the details of the ``Method`` implementation. 5 | 6 | .. autoclass:: boa.code.method.method 7 | :members: 8 | :undoc-members: 9 | -------------------------------------------------------------------------------- /docs/source/boa/code/module.rst: -------------------------------------------------------------------------------- 1 | boa.code.module.Module 2 | ====================== 3 | 4 | What follows are the details of the ``Module`` implementation. 5 | 6 | .. autoclass:: boa.code.module.Module 7 | :members: 8 | :undoc-members: 9 | -------------------------------------------------------------------------------- /docs/source/boa/code/pytoken.rst: -------------------------------------------------------------------------------- 1 | boa.code.pytoken.PyToken 2 | ======================== 3 | 4 | What follows are the details of the ``PyToken`` implementation. 5 | 6 | .. autoclass:: boa.code.pytoken.PyToken 7 | :members: 8 | :undoc-members: -------------------------------------------------------------------------------- /docs/source/boa/code/vmtoken.rst: -------------------------------------------------------------------------------- 1 | boa.code.vmtoken.VMToken 2 | ======================== 3 | 4 | What follows are the details of the ``VMToken`` implementation. 5 | 6 | .. autoclass:: boa.code.vmtoken.VMToken 7 | :members: 8 | :undoc-members: -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:16.04 2 | 3 | RUN apt-get update && apt-get -y install python3-dev python3-pip 4 | 5 | RUN pip3 install astor logzero coz-bytecode neo-boa 6 | 7 | COPY compiler.py /compiler.py 8 | 9 | CMD python3 compiler.py 10 | -------------------------------------------------------------------------------- /boa_test/example/IterTest6.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import range 4 | 5 | 6 | def Main(): 7 | 8 | items = range(0, 10) 9 | 10 | count = 0 11 | 12 | for i in items: 13 | count += 1 14 | 15 | return count 16 | -------------------------------------------------------------------------------- /boa_test/example/ArrayTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(index): 5 | 6 | j = 3 7 | arr = [1, j + 3, 3, 4, gethting(), 6, 7, 8, 9] 8 | 9 | m = arr[index] 10 | 11 | return m 12 | 13 | 14 | def gethting(): 15 | 16 | return 8 17 | -------------------------------------------------------------------------------- /boa_test/example/MethodTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(b1, b2): 5 | 6 | q = 4 7 | 8 | c2 = add_things(b1, b2) 9 | 10 | return q + c2 11 | 12 | 13 | def add_things(a, b): 14 | 15 | result = a + b 16 | 17 | return result 18 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods8.py: -------------------------------------------------------------------------------- 1 | def method(operation, args): 2 | if operation == 'add': 3 | a = args[0] 4 | b = args[1] 5 | return add(a, b) 6 | else: 7 | return False 8 | 9 | 10 | def add(a, b): 11 | return a + b 12 | -------------------------------------------------------------------------------- /docs/source/boa/code/expression.rst: -------------------------------------------------------------------------------- 1 | boa.code.expression.Expression 2 | ============================== 3 | 4 | What follows are the details of the ``Expression`` implementation. 5 | 6 | .. autoclass:: boa.code.expression.Expression 7 | :members: 8 | :undoc-members: -------------------------------------------------------------------------------- /boa_test/example/ModuleMethodTest1.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import sha1 3 | 4 | MYSHA = sha1('abc') 5 | 6 | 7 | def Main(): 8 | 9 | m = 3 10 | 11 | j2 = sha1('abc') 12 | 13 | j3 = MYSHA 14 | 15 | # print(j2) 16 | 17 | return j2 == j3 18 | -------------------------------------------------------------------------------- /boa_test/example/ByteArrayTest3.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import concat 3 | 4 | 5 | def Main(): 6 | 7 | m = bytearray(b'\x01\x02') 8 | 9 | j = get_ba() 10 | 11 | return concat(m, j) 12 | 13 | 14 | def get_ba(): 15 | 16 | return bytearray(b'\xaa\xfe') 17 | -------------------------------------------------------------------------------- /boa_test/example/CompareTest3.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(): 3 | 4 | a = 3 5 | 6 | b = 2 7 | 8 | m = 0 9 | 10 | if a < b: 11 | print("lt") 12 | 13 | else: 14 | 15 | print("Gt") 16 | m = 4 17 | 18 | print("ok!!") 19 | 20 | return m 21 | -------------------------------------------------------------------------------- /boa_test/example/DictTest5_ShouldNotCompile.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | # this file should/does not compile 7 | 8 | d = { 9 | 'a': 1, 10 | 'b': {'a': 2}, # loading a dict inline will not compile 11 | } 12 | 13 | return d['b'] 14 | -------------------------------------------------------------------------------- /boa_test/example/demo/Demo2.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Runtime import GetTrigger 2 | from boa.interop.Neo.TriggerType import Application, Verification 3 | # from boa.builtins import concat 4 | 5 | 6 | def Main(): 7 | 8 | trigger = GetTrigger() 9 | 10 | return trigger == Application() 11 | -------------------------------------------------------------------------------- /boa_test/example/ConcatTest.py: -------------------------------------------------------------------------------- 1 | from boa.builtins import concat 2 | 3 | 4 | def Main(): 5 | 6 | str1 = 'hello' 7 | str2 = 'world' 8 | 9 | str3 = concat(str1, str2) 10 | 11 | # this ends up being 'worldhello' 12 | # need to reverse the parameters... 13 | 14 | return str3 15 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [bumpversion] 2 | current_version = 0.7.2 3 | 4 | [pycodestyle] 5 | ignore = E721,E402,W291,E741,W601 6 | max-line-length = 63556 7 | 8 | [build_sphinx] 9 | source-dir = docs/source 10 | build-dir = docs/build 11 | all_files = 1 12 | 13 | [upload_sphinx] 14 | upload-dir = docs/build/html 15 | 16 | -------------------------------------------------------------------------------- /boa_test/example/IterTest8.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import range 4 | 5 | 6 | def Main(): 7 | 8 | rangestart = 2 9 | count = 0 10 | 11 | for i in range(rangestart, getrangeend()): 12 | count += 1 13 | 14 | return count 15 | 16 | 17 | def getrangeend(): 18 | return 8 19 | -------------------------------------------------------------------------------- /boa_test/example/ArrayTest4.py: -------------------------------------------------------------------------------- 1 | # tested 2 | from boa.builtins import list 3 | from boa.interop.Neo.Runtime import Notify 4 | 5 | 6 | def Main(): 7 | 8 | m = 3 9 | 10 | j = list(length=m) 11 | 12 | j[0] = 3 13 | 14 | j[1] = 2 15 | 16 | q = j[0] 17 | 18 | Notify(q) 19 | 20 | return j 21 | -------------------------------------------------------------------------------- /boa_test/example/MethodTest4.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | a = 1 7 | 8 | b = 10 9 | 10 | c = 20 11 | 12 | d = add(a, b, 10) 13 | 14 | d2 = add(d, d, d) 15 | 16 | return d2 17 | 18 | 19 | def add(a, b, c): 20 | 21 | result = a + b + c 22 | 23 | return result 24 | -------------------------------------------------------------------------------- /boa/code/action.py: -------------------------------------------------------------------------------- 1 | 2 | class action(): 3 | 4 | method_name = None 5 | event_name = None 6 | event_args = None 7 | 8 | def __init__(self, blocks): 9 | self.method_name = blocks[-1].arg 10 | self.event_args = [instr.arg for instr in blocks[1:-2]] 11 | self.event_name = self.event_args[0] 12 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods6.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | def add(a, b): 15 | return a + b 16 | -------------------------------------------------------------------------------- /boa_test/example/ByteArrayTest.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import concat 3 | 4 | 5 | def Main(): 6 | 7 | c = b'\x01\x04\xaf\x09' 8 | 9 | l = len(c) 10 | 11 | b = c[2:l] 12 | 13 | j = b'\x01\x02\x03\x04\x05\x06\x07' 14 | 15 | k = concat(c, j) 16 | 17 | m = k[3:6] 18 | 19 | return concat(m, b) 20 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods3.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_method(String, Array, Any) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | def add(a, b): 15 | return a + b 16 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods7.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String, Array) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | def add(a, b): 15 | return a + b 16 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/AppCallTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.App import RegisterAppCall 2 | 3 | CalculatorContract = RegisterAppCall('86d58778c8d29e03182f38369f0d97782d303cc0', 'operation', 'a', 'b') 4 | 5 | 6 | def Main(operation, a, b): 7 | 8 | result = CalculatorContract(operation, a, b) 9 | 10 | return result 11 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/AppCallTest2.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.App import RegisterAppCall 2 | 3 | CalculatorContract = RegisterAppCall('9e17cd49e4a198e8825b775bd685a4d0818a757', 'operation', 'a', 'b') 4 | 5 | 6 | def Main(operation, a, b): 7 | 8 | result = CalculatorContract(operation, a, b) 9 | 10 | return result 11 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/DynamicAppCallTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.App import DynamicAppCall 2 | from boa.interop.Neo.Runtime import Notify 3 | 4 | # Note this is a new api, not ready for mainnet yet 5 | 6 | 7 | def Main(hash, operation, a, b): 8 | 9 | res = DynamicAppCall(hash, operation, a, b) 10 | 11 | return res 12 | -------------------------------------------------------------------------------- /requirements_dev.txt: -------------------------------------------------------------------------------- 1 | astor>=0.6.2 2 | logzero==1.5.0 3 | coz-bytecode==0.5.1 4 | neo-python==0.7.7 5 | Sphinx==1.6.4 6 | sphinx-rtd-theme==0.2.4 7 | sphinxcontrib-websupport==1.0.1 8 | pycodestyle==2.4.0 9 | Pygments>=2.5.1 10 | requests>=2.2.0 11 | autopep8==1.3.5 12 | twine>=1.10.0 13 | wheel>=0.30.0 14 | coverage==4.5.1 15 | 16 | -------------------------------------------------------------------------------- /boa/interop/Neo/Witness.py: -------------------------------------------------------------------------------- 1 | 2 | class Witness: 3 | 4 | @property 5 | def VerificationScript(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetVerificationScript(self) 11 | 12 | 13 | def GetVerificationScript(witness): 14 | """ 15 | 16 | :param witness: 17 | """ 18 | pass 19 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods2.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String, Array, Any) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | def add(a, b): 15 | return a + b 16 | -------------------------------------------------------------------------------- /boa/interop/Neo/App.py: -------------------------------------------------------------------------------- 1 | 2 | def RegisterAppCall(smart_contract_hash, *args): 3 | """ 4 | 5 | :param smart_contract_hash: 6 | :param args: 7 | """ 8 | pass 9 | 10 | 11 | def DynamicAppCall(smart_contract_hash, *args): 12 | """ 13 | 14 | :param smart_contract_hash: 15 | :param args: 16 | """ 17 | pass 18 | -------------------------------------------------------------------------------- /boa_test/example/ArrayTest3.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | # lets have fun 7 | 8 | m = [[1, 2, 3], 'fun', 'cool', ['a', 'b', 'c']] 9 | 10 | answer = m[0] 11 | 12 | sub = m[3] 13 | 14 | sublen = len(sub) 15 | print(sublen) 16 | subitem = sub[0] 17 | print(subitem) 18 | 19 | return answer 20 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods5.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String, Array, ByteArray, Any) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | def add(a, b): 15 | return a + b 16 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/AppCallTest3.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.App import RegisterAppCall 2 | 3 | CalculatorContract = RegisterAppCall(b'W\xa7\x18\x08MZh\xbdu\xb7%\x88\x8e\x19J\x9e\xd4|\xe1\xe3\xaa', 'operation', 'a', 'b') 4 | 5 | 6 | def Main(operation, a, b): 7 | 8 | result = CalculatorContract(operation, a, b) 9 | 10 | return result 11 | -------------------------------------------------------------------------------- /boa/interop/Neo/InvocationTransaction.py: -------------------------------------------------------------------------------- 1 | 2 | class InvocationTransaction: 3 | 4 | @property 5 | def Script(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetScript(self) 11 | 12 | 13 | def GetScript(invocation_transaction): 14 | """ 15 | 16 | :param invocation_transaction: 17 | """ 18 | pass 19 | -------------------------------------------------------------------------------- /boa_test/example/MethodTest5.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | mylist = [1, 4, 6, 9, 13] 7 | 8 | d2 = add(mylist[0], mylist[2], get_a_value(mylist[1])) 9 | 10 | return d2 11 | 12 | 13 | def add(a, b, c): 14 | 15 | result = a + b + c 16 | 17 | return result 18 | 19 | 20 | def get_a_value(m): 21 | 22 | return m + 4 23 | -------------------------------------------------------------------------------- /boa_test/example/SliceTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | m = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08') 7 | 8 | # this is a test to see if slice notation without specifying an end 9 | # is functional 10 | # s1 = m[2:] # it is not 11 | 12 | # without specifying beginning it is: 13 | s2 = m[:4] 14 | 15 | return s2 16 | -------------------------------------------------------------------------------- /boa_test/example/AppendTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Runtime import Notify 2 | 3 | 4 | def Main(): 5 | 6 | m = [1, 2, 2] 7 | 8 | m.append(7) 9 | 10 | q = [6, 7] 11 | 12 | l = 'howdy' 13 | 14 | m.append(l) 15 | 16 | m.append(q) 17 | 18 | m.append(b'\x01') 19 | 20 | answer = q[0] 21 | 22 | # Notify(m) 23 | 24 | return m[5] 25 | -------------------------------------------------------------------------------- /boa_test/example/WhileTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | """ 6 | 7 | :return: 8 | """ 9 | a = 0 10 | b = 0 11 | 12 | c = 22 13 | 14 | while a < 7: 15 | 16 | a = a + 1 17 | 18 | if a == 7: 19 | break 20 | 21 | while c > 20: 22 | c = c - 5 23 | 24 | return a + b + c # expect 24 25 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods1.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String, Array, Any) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | @abi_method(Integer, Integer, Integer) 15 | def add(a, b): 16 | return a + b 17 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | **What current issue(s) from Github does this address?** 3 | 4 | **What problem does this PR solve?** 5 | 6 | **How did you solve this problem?** 7 | 8 | **How did you make sure your solution works?** 9 | 10 | **Are there any special changes in the code that we should be aware of?** 11 | 12 | **Is there anything else we should know?** 13 | 14 | -------------------------------------------------------------------------------- /boa_test/example/AbiMethods4.py: -------------------------------------------------------------------------------- 1 | from boa.abi import * 2 | 3 | 4 | @abi_entry_point(String, Array, Any) 5 | def main(operation, args): 6 | if operation == 'add': 7 | a = args[0] 8 | b = args[1] 9 | return add(a, b) 10 | else: 11 | return False 12 | 13 | 14 | @abi_entry_point(Integer, Integer, Integer) 15 | def add(a, b): 16 | return a + b 17 | -------------------------------------------------------------------------------- /boa_test/example/Fibonacci.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(fibnumber): 3 | """ 4 | 5 | :param fibnumber: 6 | :return: 7 | """ 8 | fibresult = fibR(fibnumber) 9 | 10 | return fibresult 11 | 12 | 13 | def fibR(n): 14 | """ 15 | 16 | :param n: 17 | :return: 18 | """ 19 | if n == 1 or n == 2: 20 | return 1 21 | 22 | return fibR(n - 1) + fibR(n - 2) 23 | -------------------------------------------------------------------------------- /boa_test/example/ModuleVariableTest.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | CONST = 8 4 | OTHERCONTS = 1232 5 | 6 | WHAT = 5 7 | 8 | 9 | def Main(): 10 | """ 11 | 12 | :return: 13 | """ 14 | print("do main?") 15 | j = CONST 16 | 17 | b = bleh() 18 | 19 | return CONST + OTHERCONTS + WHAT + b + j 20 | 21 | 22 | def bleh(): 23 | """ 24 | 25 | :return: 26 | """ 27 | return 2 + WHAT 28 | -------------------------------------------------------------------------------- /boa/interop/Neo/TriggerType.py: -------------------------------------------------------------------------------- 1 | 2 | def Verification(): 3 | """ 4 | 5 | :return: 6 | """ 7 | pass 8 | 9 | 10 | def VerificationR(): 11 | """ 12 | 13 | :return: 14 | """ 15 | pass 16 | 17 | 18 | def Application(): 19 | """ 20 | 21 | :return: 22 | """ 23 | pass 24 | 25 | 26 | def ApplicationR(): 27 | """ 28 | 29 | :return: 30 | """ 31 | pass 32 | -------------------------------------------------------------------------------- /boa_test/example/DictTest4.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | j = 10 7 | 8 | d = { 9 | 'a': 1, 10 | 'b': 4, 11 | 4: 'blah', 12 | 'm': j, 13 | 'z': [1, 3, 4, 5, 'abcd', j], 14 | 'mcalll': mymethod(1, 4) 15 | } 16 | 17 | j4 = d['mcalll'] 18 | 19 | return j4 + d['z'][3] 20 | 21 | 22 | def mymethod(a, b): 23 | 24 | return a + b 25 | -------------------------------------------------------------------------------- /boa_test/example/ConcatTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import concat 4 | 5 | 6 | def Main(operation, args): 7 | if operation == 'concat': 8 | return do_concat(args) 9 | else: 10 | return False 11 | 12 | 13 | def do_concat(args): 14 | if len(args) > 1: 15 | a = args[0] 16 | b = args[1] 17 | output = concat(a, b) 18 | return output 19 | return False 20 | -------------------------------------------------------------------------------- /boa_test/example/IterTest4.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import concat 4 | 5 | 6 | def Main(): 7 | 8 | items = [0, 1, 2] 9 | 10 | items2 = ['a', 'b', 'c', 'd'] 11 | count = 0 12 | 13 | blah = b'' 14 | 15 | for i in items: 16 | 17 | for j in items2: 18 | 19 | blah = concat(blah, j) 20 | 21 | count += 1 22 | 23 | blah = concat(blah, count) 24 | 25 | return blah 26 | -------------------------------------------------------------------------------- /boa_test/example/ByteArrayTest2.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import concat 3 | 4 | 5 | def Main(ba1, ba2): 6 | 7 | m = ba2[1:2] # but you can do this instead 8 | 9 | # strings and byte arrays work the same 10 | mystr = 'staoheustnau' 11 | 12 | # this will not work 13 | # m = mystr[3] 14 | 15 | # but this will 16 | m = mystr[3:5] 17 | 18 | # 19 | m = ba1[1:len(ba1)] 20 | 21 | return concat(m, concat(mystr, ba2)) 22 | -------------------------------------------------------------------------------- /boa_test/example/IterTest3.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | items = [0, 1, 2] 7 | 8 | count = 0 9 | 10 | for i in items: 11 | 12 | count += i 13 | 14 | if i == 1: 15 | print("ONE!") 16 | 17 | count += what() 18 | 19 | else: 20 | count -= minus(i) 21 | 22 | return count 23 | 24 | 25 | def what(): 26 | 27 | return 8 28 | 29 | 30 | def minus(a): 31 | return a + 1 32 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/EventTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Action import RegisterAction 4 | 5 | Transfer = RegisterAction('transfer_test', 'from', 'to', 'amount') 6 | 7 | Refund = RegisterAction('refund', 'to', 'amount') 8 | 9 | 10 | def Main(): 11 | 12 | a = 2 13 | 14 | b = 5 15 | 16 | c = a + b 17 | 18 | Transfer(a, b, c) 19 | 20 | to = 'me' 21 | amount = 52 22 | 23 | Refund(to, amount) 24 | 25 | return c 26 | -------------------------------------------------------------------------------- /boa/interop/Neo/Enumerator.py: -------------------------------------------------------------------------------- 1 | 2 | class Enumerator: 3 | 4 | @property 5 | def Value(self): 6 | return EnumeratorValue(self) 7 | 8 | def Next(self): 9 | return EnumeratorNext(self) 10 | 11 | 12 | def EnumeratorCreate(items): 13 | pass 14 | 15 | 16 | def EnumeratorNext(enumerator): 17 | pass 18 | 19 | 20 | def EnumeratorValue(enumerator): 21 | pass 22 | 23 | 24 | def EnumeratorConcat(enumerator1, enumerator2): 25 | pass 26 | -------------------------------------------------------------------------------- /boa_test/example/IterTest5.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import concat 4 | from boa.interop.Neo.Runtime import Notify 5 | 6 | 7 | def Main(): 8 | 9 | items = [0, 1, 2] 10 | 11 | items2 = ['a', 'b', 'c', 'd'] 12 | count = 0 13 | 14 | for i in items: # 3 15 | 16 | count += 1 17 | 18 | for j in items2: # 4 19 | 20 | count += 1 21 | 22 | for k in items: # 3 23 | count += 1 24 | 25 | return count 26 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/ExecutionEngineTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.System.ExecutionEngine import * 2 | 3 | 4 | def Main(operation): 5 | 6 | if operation == 'executing_sh': 7 | return GetExecutingScriptHash() 8 | 9 | elif operation == 'script_container': 10 | return GetScriptContainer() 11 | 12 | elif operation == 'calling_sh': 13 | return GetCallingScriptHash() 14 | 15 | elif operation == 'entry_sh': 16 | return GetEntryScriptHash() 17 | 18 | return 'unknown' 19 | -------------------------------------------------------------------------------- /boa_test/example/ArrayTest1.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | m = [2, 4, 1, 5 + 12] 7 | 8 | # we cant do this. once you create an array you cant extend it 9 | # m[5] = 8 10 | 11 | m[2] = 7 + 10 12 | 13 | m2 = [9, 10, 11, 12] 14 | 15 | # we can change items 16 | m2[0] = 4 17 | 18 | # we can access items in the array! 19 | q = m[1] 20 | 21 | # m3 = m + m2 // VM wont support concatenating arrays for now 22 | 23 | # returns 1 aka true 24 | return m2[0] == q 25 | -------------------------------------------------------------------------------- /boa_test/example/DictTestHasKey.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import has_key 4 | 5 | 6 | def Main(): 7 | 8 | d = { 9 | 'a': 1, 10 | 'b': 4, 11 | } 12 | 13 | result = 0 14 | 15 | if has_key(d, 'a'): 16 | result += 2 17 | 18 | if not d.has_key('j'): 19 | result += 3 20 | 21 | if 'b' in d: 22 | 23 | print("b i si in d:") 24 | result += 17 25 | else: 26 | 27 | print("b not in d") 28 | 29 | return result # should be 22 30 | -------------------------------------------------------------------------------- /boa_test/example/NoneTest.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | """ 5 | 6 | :return: 7 | """ 8 | a = None # this gets coerced to 0 9 | 10 | b = 1 11 | 12 | if a is None: # this evaluates to true ( which it is ) 13 | b = 2 14 | 15 | c = a + b # this evaluates to b + 0, so in this case 2 16 | 17 | # in python, the expected behavior for this would be to raise 18 | # a type error, since you can't add NoneType to an int 19 | # in the vm, its all ok i guess 20 | 21 | return c 22 | -------------------------------------------------------------------------------- /boa/interop/SmartContract.py: -------------------------------------------------------------------------------- 1 | 2 | class SmartContract: 3 | 4 | def Sha1(data): 5 | """ 6 | 7 | """ 8 | pass 9 | 10 | def Sha256(data): 11 | """ 12 | 13 | """ 14 | pass 15 | 16 | def Hash160(data): 17 | """ 18 | 19 | """ 20 | pass 21 | 22 | def Hash256(data): 23 | """ 24 | 25 | """ 26 | pass 27 | 28 | def VerifySignature(pubkey, signature): 29 | """ 30 | 31 | :param signature: 32 | """ 33 | pass 34 | -------------------------------------------------------------------------------- /boa/interop/Neo/Input.py: -------------------------------------------------------------------------------- 1 | 2 | class TransactionInput: 3 | 4 | @property 5 | def Hash(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetInputHash(self) 11 | 12 | @property 13 | def Index(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetIndex(self) 19 | 20 | 21 | def GetInputHash(input): 22 | """ 23 | 24 | :param input: 25 | """ 26 | pass 27 | 28 | 29 | def GetIndex(input): 30 | """ 31 | 32 | :param input: 33 | """ 34 | pass 35 | -------------------------------------------------------------------------------- /boa_test/example/ArrayTest2.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(): 3 | 4 | # lets have fun with strings 5 | 6 | m = ['awesome', 'fun', 'cool', 'neo'] 7 | 8 | q = m[1] 9 | 10 | m2 = [1, 'wat', 'huzzah', 8] 11 | 12 | q2 = m[3] 13 | 14 | m3 = [b'\x00', b'\x20', b'\xff', b'\xa0'] 15 | 16 | q3 = m3[3] 17 | 18 | m4 = [bytearray(b'\x0f\xf0'), bytearray(b'\xff\xff')] 19 | 20 | # this doesnt work 21 | q4 = m4[1] 22 | 23 | h = [2, m2[1], 'hello'] 24 | 25 | j = h[1] 26 | 27 | print(j) # prints 'wat' 28 | 29 | return q3 30 | -------------------------------------------------------------------------------- /docs/source/basicusage.rst: -------------------------------------------------------------------------------- 1 | Basic Usage 2 | ----------- 3 | 4 | The compiler may be used as follows 5 | 6 | :: 7 | 8 | from boa.compiler import Compiler 9 | 10 | Compiler.load_and_save('path/to/your/file.py') 11 | 12 | 13 | For legacy purposes, if you wish to compile without NEP8 stack isolation functionality, you may do the following: 14 | 15 | :: 16 | 17 | from boa.compiler import Compiler 18 | 19 | Compiler.load_and_save('path/to/your/file.py', use_nep=False) 20 | 21 | 22 | 23 | See `boa.compiler.Compiler` and other modules for more advanced usage. 24 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/RuntimeTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Runtime import * 4 | 5 | 6 | def Main(operation, arg): 7 | 8 | if operation == 'get_trigger': 9 | return GetTrigger() 10 | 11 | elif operation == 'check_witness': 12 | return CheckWitness(arg) 13 | 14 | elif operation == 'get_time': 15 | return GetTime() 16 | 17 | elif operation == 'log': 18 | Log(arg) 19 | return True 20 | 21 | elif operation == 'notify': 22 | Notify(arg) 23 | return True 24 | 25 | return 'unknown' 26 | -------------------------------------------------------------------------------- /docs/source/boa/interop/executionengine.rst: -------------------------------------------------------------------------------- 1 | ========================== 2 | [Interop] Execution Engine 3 | ========================== 4 | 5 | The items below are used for gathering reference about the current execution of the Neo Virtual Machine. 6 | Because all items below are implemented in the Neo Virtual Machine, their source is not available here. 7 | Please see the `neo-python `_ project if you want to know more about their exact implementation. 8 | 9 | Methods 10 | ------- 11 | 12 | .. automodule:: boa.interop.System.ExecutionEngine 13 | -------------------------------------------------------------------------------- /boa_test/example/CompareTest1.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(a, b, c, d): 5 | 6 | m = 0 7 | 8 | if a > b: 9 | 10 | if c > d: 11 | 12 | m = 3 13 | 14 | else: 15 | 16 | if b > c: 17 | 18 | return 8 19 | 20 | else: 21 | 22 | return 10 23 | 24 | else: 25 | 26 | if c > d: 27 | 28 | m = 1 29 | 30 | else: 31 | 32 | if b < c: 33 | 34 | return 11 35 | 36 | else: 37 | 38 | m = 22 39 | 40 | return m 41 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/StorageTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Storage import Get, Put, Delete, GetContext 2 | from boa.interop.Neo.Runtime import Notify 3 | 4 | context = GetContext() 5 | 6 | 7 | def Main(operation, arg, val): 8 | 9 | print("context") 10 | 11 | if operation == 'sget': 12 | 13 | return Get(context, arg) 14 | 15 | elif operation == 'sput': 16 | 17 | Put(context, arg, val) 18 | return True 19 | 20 | elif operation == 'sdel': 21 | 22 | Delete(context, arg) 23 | return True 24 | 25 | return 'unknown operation' 26 | -------------------------------------------------------------------------------- /docs/source/contribute.rst: -------------------------------------------------------------------------------- 1 | Contribute 2 | ========== 3 | 4 | 5 | Help 6 | ---- 7 | 8 | - Open a new `issue`_ if you encounter a problem. 9 | - Or ping **@localhuman** on the `NEO Slack`_. 10 | - Pull requests are welcome. New features, writing tests and 11 | documentation are all needed. 12 | 13 | Donations 14 | --------- 15 | 16 | Accepted at Neo address **ATEMNPSjRVvsXmaJW4ZYJBSVuJ6uR2mjQU**. 17 | 18 | .. _issue: https://github.com/CityOfZion/neo-boa/issues/new 19 | .. _NEO Slack: https://join.slack.com/t/neoblockchainteam/shared_invite/MjE3ODMxNDUzMDE1LTE1MDA4OTY3NDQtNTMwM2MyMTc2NA 20 | -------------------------------------------------------------------------------- /boa/interop/Neo/Attribute.py: -------------------------------------------------------------------------------- 1 | 2 | class TransactionAttribute: 3 | 4 | @property 5 | def Usage(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetUsage(self) 11 | 12 | @property 13 | def Data(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetData(self) 19 | 20 | 21 | def GetUsage(transaction_attr): 22 | """ 23 | 24 | :param transaction_attr: 25 | """ 26 | pass 27 | 28 | 29 | def GetData(transaction_attr): 30 | """ 31 | 32 | :param transaction_attr: 33 | """ 34 | pass 35 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/TriggerTypeTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.TriggerType import Application, Verification, ApplicationR, VerificationR 4 | from boa.interop.Neo.Runtime import GetTrigger 5 | 6 | 7 | def Main(arg): 8 | 9 | if arg == 1: 10 | return Application() 11 | 12 | elif arg == 2: 13 | return Verification() 14 | 15 | elif arg == 3: 16 | 17 | if GetTrigger() == Application(): 18 | return b'\x20' 19 | 20 | elif arg == 4: 21 | return ApplicationR() 22 | 23 | elif arg == 5: 24 | return VerificationR() 25 | 26 | return -1 27 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 3.6 4 | 5 | matrix: 6 | include: 7 | - python: 3.7 8 | dist: xenial 9 | sudo: true 10 | 11 | env: 12 | - SKIP_DEPS_CHECK=1 13 | 14 | addons: 15 | apt: 16 | packages: 17 | - libleveldb-dev 18 | - libsqlite3-dev 19 | 20 | 21 | # command to install dependencies 22 | install: 23 | - pip install -r requirements_test.txt 24 | - pip install coveralls 25 | 26 | # command to run tests 27 | script: 28 | - coverage run -m unittest discover boa_test 29 | - pycodestyle boa 30 | - pycodestyle boa_test 31 | 32 | 33 | after_success: 34 | coveralls 35 | -------------------------------------------------------------------------------- /boa/interop/Neo/TransactionType.py: -------------------------------------------------------------------------------- 1 | 2 | def MinerTransaction(): 3 | pass 4 | 5 | 6 | def IssueTransaction(): 7 | pass 8 | 9 | 10 | def ClaimTransaction(): 11 | pass 12 | 13 | 14 | def EnrollmentTransaction(): 15 | pass 16 | 17 | 18 | def VotingTransaction(): 19 | pass 20 | 21 | 22 | def RegisterTransaction(): 23 | pass 24 | 25 | 26 | def ContractTransaction(): 27 | pass 28 | 29 | 30 | def StateTransaction(): 31 | pass 32 | 33 | 34 | def AgencyTransaction(): 35 | pass 36 | 37 | 38 | def PublishTransaction(): 39 | pass 40 | 41 | 42 | def InvocationTransaction(): 43 | pass 44 | -------------------------------------------------------------------------------- /boa_test/example/DictTestValues.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import values, concat 4 | from boa.interop.Neo.Runtime import Notify 5 | 6 | 7 | def Main(): 8 | 9 | j = 10 10 | 11 | d = { 12 | 'a': 1, 13 | 'b': 4, 14 | 4: 22, 15 | 'm': j, 16 | } 17 | 18 | output = 0 19 | for item in values(d): 20 | output += item 21 | 22 | d2 = { 23 | 't': 5, 24 | 'r': 6, 25 | 's': 7 26 | } 27 | 28 | for item in d2.values(): 29 | 30 | output += item 31 | 32 | return output 33 | 34 | 35 | def mymethod(a, b): 36 | 37 | return a + b 38 | -------------------------------------------------------------------------------- /boa_test/example/MethodTest3.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | 5 | a = [1, 2, 3, 4, 5] 6 | 7 | a2 = a[1] 8 | 9 | a3 = a[2] 10 | 11 | e = add(1, 2, 3, 4, a2) 12 | 13 | first_item = get_first_item(a) 14 | 15 | return e + first_item 16 | 17 | 18 | def add(a, b, c, d, e): 19 | """ 20 | 21 | :param a: 22 | :param b: 23 | :param c: 24 | :param d: 25 | :param e: 26 | :return: 27 | """ 28 | result = a + b + c + d + e 29 | 30 | return result 31 | 32 | 33 | def get_first_item(array_item): 34 | """ 35 | 36 | :param array_item: 37 | :return: 38 | """ 39 | return array_item[0] 40 | -------------------------------------------------------------------------------- /boa_test/example/OpCallTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import sha1, sha256, hash160, hash256 4 | 5 | 6 | def Main(operation, a, b): 7 | 8 | if operation == 'omin': 9 | return min(a, b) 10 | 11 | elif operation == 'omax': 12 | return max(a, b) 13 | 14 | elif operation == 'oabs': 15 | return abs(a) 16 | 17 | elif operation == 'sha1': 18 | return sha1(a) 19 | 20 | elif operation == 'sha256': 21 | return sha256(a) 22 | 23 | elif operation == 'hash160': 24 | return hash160(a) 25 | 26 | elif operation == 'hash256': 27 | return hash256(a) 28 | 29 | return 'unknown' 30 | -------------------------------------------------------------------------------- /boa_test/example/EqualityTest.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(): 3 | 4 | print('hello!') 5 | 6 | a = b'\x03' 7 | 8 | b = 3 9 | 10 | if a == b: 11 | 12 | print("equal!!") 13 | 14 | else: 15 | 16 | print("not equal!") 17 | 18 | if sample_method_call() == sample_method_call_2(): 19 | print("method equal") 20 | else: 21 | print("method not equal") 22 | 23 | if a is b: 24 | 25 | print("is!") 26 | 27 | else: 28 | 29 | print("not is!") 30 | 31 | return True 32 | 33 | 34 | def sample_method_call(): 35 | 36 | return 2 37 | 38 | 39 | def sample_method_call_2(): 40 | 41 | return 2 42 | -------------------------------------------------------------------------------- /boa_test/example/BinopTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(operation, a, b): 5 | 6 | if operation == '&': 7 | return a & b 8 | 9 | elif operation == '|': 10 | return a | b 11 | 12 | elif operation == '^': 13 | return a ^ b 14 | 15 | elif operation == '>>': 16 | return a >> b 17 | 18 | elif operation == '<<': 19 | return a << b 20 | 21 | elif operation == '%': 22 | return a % b 23 | 24 | elif operation == '//': 25 | return a // b 26 | 27 | elif operation == '/': 28 | return a / b 29 | 30 | elif operation == '~': 31 | return ~a 32 | 33 | return 'unknown' 34 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = neo-boa 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /boa_test/example/blockchain/ContractTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Blockchain import GetContract 4 | from boa.interop.Neo.Contract import * 5 | 6 | 7 | def Main(operation, ctr): 8 | 9 | if operation == 'get_contract': 10 | return GetContract(ctr) 11 | 12 | elif operation == 'get_script': 13 | return GetContract(ctr).Script 14 | 15 | elif operation == 'get_storage_context': 16 | return GetContract(ctr).StorageContext 17 | 18 | elif operation == 'get_payable': 19 | return GetContract(ctr).IsPayable 20 | 21 | elif operation == 'destroy': 22 | Destroy() 23 | return True 24 | 25 | return 'unknown operation' 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = python -msphinx 7 | SPHINXPROJ = neo-boa 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /boa/interop/Neo/Storage.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def GetContext(): 4 | """ 5 | 6 | """ 7 | pass 8 | 9 | 10 | # def CurrentContext(): 11 | # return GetContext() 12 | 13 | def Get(context, key): 14 | """ 15 | 16 | :param context: 17 | :param key: 18 | """ 19 | pass 20 | 21 | 22 | def Put(context, key, value): 23 | """ 24 | 25 | :param context: 26 | :param key: 27 | :param value: 28 | """ 29 | pass 30 | 31 | 32 | def Find(ctx, needle): 33 | """ 34 | 35 | :param context: 36 | :param needle: 37 | """ 38 | pass 39 | 40 | 41 | def Delete(context, key): 42 | """ 43 | 44 | :param context: 45 | :param key: 46 | """ 47 | pass 48 | -------------------------------------------------------------------------------- /docs/source/install.rst: -------------------------------------------------------------------------------- 1 | 2 | Installation 3 | ------------ 4 | 5 | This version of the compiler requires Python 3.6 or later 6 | 7 | Using pip 8 | ^^^^^^^^^ 9 | 10 | :: 11 | 12 | pip install neo-boa 13 | 14 | Manually 15 | ^^^^^^^^ 16 | 17 | Clone the repository and navigate into the project directory. 18 | Make a Python 3 virtual environment and activate it via 19 | 20 | :: 21 | 22 | python3 -m venv venv 23 | source venv/bin/activate 24 | 25 | or to explicitly install Python 3.6, 26 | 27 | :: 28 | 29 | virtualenv -p /usr/local/bin/python3.6 venv 30 | source venv/bin/activate 31 | 32 | Then install the requirements via 33 | 34 | :: 35 | 36 | pip install -r requirements.txt 37 | -------------------------------------------------------------------------------- /docker/compiler.py: -------------------------------------------------------------------------------- 1 | import os 2 | from boa.compiler import Compiler 3 | 4 | input_file_dir = '/python-contracts' 5 | output_file_dir = '/compiled-contracts' 6 | 7 | for file in os.listdir(input_file_dir): 8 | if file.endswith('.py'): 9 | file_name = file.replace('.py','') 10 | input_file_path = os.path.join(input_file_dir, file) 11 | output_file = file_name + '.avm' 12 | output_file_path = os.path.join(output_file_dir, output_file) 13 | try: 14 | Compiler.load_and_save(path=input_file_path, output_path=output_file_path) 15 | print(' \033[92mCompiled\t{}'.format(file)) 16 | except Exception as e: 17 | print(' \033[93mFail\t\t{}\t{}'.format(file, e)) 18 | 19 | -------------------------------------------------------------------------------- /boa/cli.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import sys 3 | import os 4 | from boa import __version__ 5 | from boa.compiler import Compiler 6 | 7 | 8 | def main(): 9 | parser = argparse.ArgumentParser() 10 | parser.add_argument("--version", action="version", version=f"neo-boa v{__version__}") 11 | parser.add_argument("input", help=".py smart contract to compile") 12 | args = parser.parse_args() 13 | 14 | if not args.input.endswith(".py") or not os.path.isfile(args.input): 15 | print("Input file is not .py") 16 | sys.exit(1) 17 | 18 | Compiler.load_and_save(args.input) 19 | print(f"Wrote {args.input.replace('.py', '.avm')} to {os.path.abspath(os.curdir)}/") 20 | 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /boa_test/example/DictTestKeys.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.builtins import keys, concat 4 | from boa.interop.Neo.Runtime import Notify 5 | 6 | 7 | def Main(): 8 | 9 | j = 10 10 | 11 | d = { 12 | 'a': 1, 13 | 'b': 4, 14 | 4: 'blah', 15 | 'm': j, 16 | 'z': [1, 3, 4, 5, 'abcd', j], 17 | 'mcalll': mymethod(1, 4) 18 | } 19 | 20 | output = '' 21 | for item in keys(d): 22 | output = concat(output, item) 23 | 24 | d2 = { 25 | 't': 5, 26 | 'r': 6, 27 | 's': 'a' 28 | } 29 | 30 | for item in d2.keys(): 31 | 32 | output = concat(output, item) 33 | 34 | return output 35 | 36 | 37 | def mymethod(a, b): 38 | 39 | return a + b 40 | -------------------------------------------------------------------------------- /boa/interop/Neo/Iterator.py: -------------------------------------------------------------------------------- 1 | 2 | class Iterator: 3 | 4 | @property 5 | def Value(self): 6 | return IterValue(self) 7 | 8 | @property 9 | def Values(self): 10 | return IterValues(self) 11 | 12 | @property 13 | def Key(self): 14 | return IterKey(self) 15 | 16 | @property 17 | def Keys(self): 18 | return IterKeys(self) 19 | 20 | def Next(self): 21 | return IterNext(self) 22 | 23 | 24 | def IterCreate(items): 25 | pass 26 | 27 | 28 | def IterNext(items): 29 | pass 30 | 31 | 32 | def IterKey(items): 33 | pass 34 | 35 | 36 | def IterKeys(items): 37 | pass 38 | 39 | 40 | def IterValue(items): 41 | pass 42 | 43 | 44 | def IterValues(items): 45 | pass 46 | -------------------------------------------------------------------------------- /boa/interop/Neo/Runtime.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def GetTrigger(): 4 | """ 5 | 6 | """ 7 | pass 8 | 9 | 10 | def CheckWitness(hash_or_pubkey): 11 | """ 12 | 13 | :param hash_or_pubkey: 14 | """ 15 | pass 16 | 17 | 18 | def Log(message): 19 | """ 20 | 21 | :param message: 22 | """ 23 | pass 24 | 25 | 26 | def Notify(arg): 27 | """ 28 | 29 | :param arg: 30 | """ 31 | pass 32 | 33 | 34 | def GetTime(): 35 | """ 36 | returns timestamp of most recent block 37 | 38 | """ 39 | pass 40 | 41 | 42 | def Serialize(item): 43 | """ 44 | Serializes an item into a bytearray 45 | """ 46 | pass 47 | 48 | 49 | def Deserialize(item): 50 | """ 51 | Deserializes an item from a bytearray 52 | """ 53 | pass 54 | -------------------------------------------------------------------------------- /boa/abi.py: -------------------------------------------------------------------------------- 1 | # write clear when using as params for @abi_entry_point and @abi_method 2 | ByteArray = 'ByteArray' 3 | Integer = 'Integer' 4 | Boolean = 'Boolean' 5 | String = 'String' 6 | Array = 'Array' 7 | Struct = 'Struct' 8 | Map = 'Map' 9 | Interface = 'Interface' 10 | Any = 'Any' 11 | Void = 'Void' 12 | 13 | types = { 14 | 'ByteArray': 'ByteArray', 15 | 'Integer': 'Integer', 16 | 'Boolean': 'Boolean', 17 | 'String': 'String', 18 | 'Array': 'Array', 19 | 'Struct': 'Struct', 20 | 'Map': 'Map', 21 | 'Interface': 'Interface', 22 | 'Any': 'Any', 23 | 'Void': 'Void' 24 | } 25 | 26 | 27 | def is_abi_type(value): 28 | return value in types 29 | 30 | 31 | def abi_method(*args): 32 | return None 33 | 34 | 35 | def abi_entry_point(*args): 36 | return None 37 | -------------------------------------------------------------------------------- /boa_test/example/ArrayArgsTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Runtime import Log 2 | from boa.builtins import concat 3 | 4 | 5 | def Main(operation, items): 6 | 7 | j = 10 8 | 9 | if operation == 'dostuff': 10 | 11 | j = 3 12 | 13 | if len(items) == 2: 14 | 15 | bytes1 = items[0] 16 | bytes2 = items[1] 17 | 18 | len1 = len(bytes1) 19 | len2 = len(bytes2) 20 | 21 | total = concat(bytes1, bytes2) 22 | 23 | # j = len1 + len2 24 | 25 | if total == 137707327489: 26 | Log("awesome!") 27 | 28 | else: 29 | Log("bad") 30 | 31 | else: 32 | 33 | j = 23 34 | 35 | elif operation == 'dont': 36 | 37 | j = 4 38 | 39 | return j 40 | -------------------------------------------------------------------------------- /boa_test/example/NotEqualTest.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(): 4 | 5 | a = 3 6 | 7 | b = 2 8 | 9 | m = 12 10 | 11 | if not a == b: # this currently works 12 | print("a not equal to b!!!") 13 | m = 21 14 | 15 | if a != b: 16 | 17 | print("numbers 2 and 3 are not equal") 18 | m = 82 19 | 20 | j = 'hello' 21 | k = 'hello' 22 | 23 | if j != k: 24 | 25 | print("string j is not equal to string k") 26 | 27 | else: 28 | 29 | print("string j is equal to string k") 30 | 31 | q = bytearray(b'\x10\x01\x80') 32 | q2 = bytearray(b'\x10\x10\x80') 33 | 34 | if q != q2: 35 | 36 | print("bytearrays m and m2 not equal") 37 | 38 | else: 39 | 40 | print("bytearrays m and m2 are equal") 41 | 42 | return m 43 | -------------------------------------------------------------------------------- /boa_test/tests/test_demo.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_Demo(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/demo/Demo1.py' % TestContract.dirname).default.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(output, ['add', 1, 3], self.GetWallet1(), '070202', '02') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBigInteger(), 7) 16 | 17 | tx, results, total_ops, engine = TestBuild(output, ['add', 2, 3], self.GetWallet1(), '070202', '02') 18 | self.assertEqual(len(results), 1) 19 | self.assertEqual(results[0].GetBigInteger(), 8) 20 | -------------------------------------------------------------------------------- /boa/interop/Neo/Output.py: -------------------------------------------------------------------------------- 1 | 2 | class TransactionOutput: 3 | 4 | @property 5 | def AssetId(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetAssetId(self) 11 | 12 | @property 13 | def Value(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetValue(self) 19 | 20 | @property 21 | def ScriptHash(self): 22 | """ 23 | 24 | :return: 25 | """ 26 | return GetScriptHash(self) 27 | 28 | 29 | def GetAssetId(output): 30 | """ 31 | 32 | :param output: 33 | """ 34 | pass 35 | 36 | 37 | def GetValue(output): 38 | """ 39 | 40 | :param output: 41 | """ 42 | pass 43 | 44 | 45 | def GetScriptHash(output): 46 | """ 47 | 48 | :param output: 49 | """ 50 | pass 51 | -------------------------------------------------------------------------------- /boa/interop/Neo/Account.py: -------------------------------------------------------------------------------- 1 | 2 | class Account: 3 | 4 | @property 5 | def ScriptHash(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetScriptHash(self) 11 | 12 | @property 13 | def Votes(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetVotes(self) 19 | 20 | 21 | def GetScriptHash(account): 22 | """ 23 | 24 | :param account: 25 | """ 26 | pass 27 | 28 | 29 | def GetVotes(account): 30 | """ 31 | 32 | :param account: 33 | """ 34 | pass 35 | 36 | 37 | def SetVotes(account, votes): 38 | """ 39 | 40 | :param account: 41 | :param votes: 42 | """ 43 | pass 44 | 45 | 46 | def GetBalance(account, asset_id): 47 | """ 48 | 49 | :param account: 50 | :param asset_id: 51 | """ 52 | pass 53 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/OutputsTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Blockchain import GetTransaction 4 | from boa.interop.Neo.Transaction import * 5 | from boa.interop.Neo.Output import * 6 | 7 | NEO = b'\x9b|\xff\xda\xa6t\xbe\xae\x0f\x93\x0e\xbe`\x85\xaf\x90\x93\xe5\xfeV\xb3J\\"\x0c\xcd\xcfn\xfc3o\xc5' 8 | GAS = b'\xe7-(iy\xeel\xb1\xb7\xe6]\xfd\xdf\xb2\xe3\x84\x10\x0b\x8d\x14\x8ewX\xdeB\xe4\x16\x8bqy,`' 9 | 10 | 11 | def Main(txid): 12 | 13 | tx = GetTransaction(txid) 14 | 15 | res = [] 16 | 17 | # we can iterate over an attribute of an object! 18 | # this is really exciting, but you'd never know it 19 | for item in tx.Outputs: 20 | subres = [] 21 | subres.append(item.Value) 22 | subres.append(item.AssetId) 23 | subres.append(item.ScriptHash) 24 | res.append(subres) 25 | 26 | return res 27 | -------------------------------------------------------------------------------- /boa/interop/Neo/Blockchain.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def GetHeight(): 4 | """ 5 | 6 | """ 7 | pass 8 | 9 | 10 | def GetHeader(height_or_hash): 11 | """ 12 | 13 | :param height_or_hash: 14 | """ 15 | pass 16 | 17 | 18 | def GetBlock(height_or_hash): 19 | """ 20 | 21 | :param height_or_hash: 22 | """ 23 | pass 24 | 25 | 26 | def GetTransaction(hash): 27 | """ 28 | 29 | :param hash: 30 | """ 31 | pass 32 | 33 | 34 | def GetAccount(script_hash): 35 | """ 36 | 37 | :param script_hash: 38 | """ 39 | pass 40 | 41 | 42 | def GetValidators(): 43 | """ 44 | 45 | """ 46 | pass 47 | 48 | 49 | def GetAsset(asset_id): 50 | """ 51 | 52 | :param asset_id: 53 | """ 54 | pass 55 | 56 | 57 | def GetContract(script_hash): 58 | """ 59 | 60 | :param script_hash: 61 | """ 62 | pass 63 | -------------------------------------------------------------------------------- /boa_test/example/EqualityTest2.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(operation): 3 | 4 | if operation == 1: 5 | a = 'deploy' 6 | 7 | b = bytearray(b'deploy\x00\x00') 8 | 9 | return a == b 10 | 11 | elif operation == 2: 12 | 13 | a = 'deploy' 14 | 15 | b = bytearray(b'deploy') 16 | 17 | return a == b 18 | 19 | elif operation == 3: 20 | 21 | a = b'deploy' 22 | b = 'deploy' 23 | return a == b 24 | 25 | elif operation == 4: 26 | 27 | a = 0 28 | b = False 29 | return a == b 30 | 31 | elif operation == 5: 32 | 33 | a = 0 34 | b = '' 35 | return a == b 36 | 37 | elif operation == 6: 38 | 39 | a = False 40 | b = '' 41 | return a == b 42 | 43 | elif operation == 7: 44 | 45 | a = False 46 | b = -1 47 | return a == b 48 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/AccountTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Blockchain import GetAccount 4 | from boa.interop.Neo.Account import * 5 | 6 | NEO = b'\x9b|\xff\xda\xa6t\xbe\xae\x0f\x93\x0e\xbe`\x85\xaf\x90\x93\xe5\xfeV\xb3J\\"\x0c\xcd\xcfn\xfc3o\xc5' 7 | GAS = b'\xe7-(iy\xeel\xb1\xb7\xe6]\xfd\xdf\xb2\xe3\x84\x10\x0b\x8d\x14\x8ewX\xdeB\xe4\x16\x8bqy,`' 8 | 9 | 10 | def Main(operation, acct): 11 | 12 | account = GetAccount(acct) 13 | 14 | if not account: 15 | return False 16 | 17 | if operation == 'get_hash': 18 | return account.ScriptHash 19 | 20 | elif operation == 'get_votes': 21 | return account.Votes 22 | 23 | elif operation == 'get_balance_gas': 24 | return GetBalance(account, GAS) 25 | 26 | elif operation == 'get_balance_neo': 27 | return GetBalance(account, NEO) 28 | 29 | return 'unknown operation' 30 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/StorageFindTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Storage import Get, Put, Delete, Find, GetContext 2 | from boa.interop.Neo.Iterator import IterNext, IterKey, IterValue 3 | from boa.interop.Neo.Runtime import Notify 4 | 5 | ctx = GetContext() 6 | 7 | 8 | def Main(query): 9 | 10 | Put(ctx, 'prefix1euo', 1) 11 | Put(ctx, 'prefix1e', 2) 12 | Put(ctx, 'prefix1__osetuh', 3) 13 | 14 | Put(ctx, 'blah', 'Hello Storage Find') 15 | 16 | result_iter = Find(ctx, query) 17 | 18 | items = [] 19 | keys = [] 20 | count = 0 21 | while result_iter.IterNext(): 22 | val = result_iter.IterValue() 23 | items.append(val) 24 | keys.append(result_iter.IterKey()) 25 | if query == 'pre' and count == 1: 26 | break 27 | 28 | count += 1 29 | 30 | if query == 'pref': 31 | return keys 32 | 33 | return items 34 | -------------------------------------------------------------------------------- /boa_test/example/MethodTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | 4 | def Main(): 5 | 6 | a = 1 7 | 8 | b = 2 9 | 10 | c = stuff() # 6 11 | 12 | d = stuff2() # 2 13 | 14 | e = stuff8() 15 | 16 | f = blah() # 9 17 | 18 | h = prevcall() # 6 19 | 20 | return a + c + d + f + b + h 21 | 22 | 23 | def stuff(): 24 | """ 25 | 26 | :return: 27 | """ 28 | a = 4 29 | 30 | b = 2 31 | 32 | return a + b 33 | 34 | 35 | def stuff2(): 36 | """ 37 | 38 | :return: 39 | """ 40 | a = 8 41 | 42 | j = 10 43 | 44 | return j - a 45 | 46 | 47 | def prevcall(): 48 | """ 49 | 50 | :return: 51 | """ 52 | return stuff() 53 | 54 | 55 | def stuff8(): 56 | """ 57 | 58 | :return: 59 | """ 60 | q = 'hello' 61 | 62 | return q 63 | 64 | 65 | def blah(): 66 | """ 67 | 68 | :return: 69 | """ 70 | return 1 + 8 71 | -------------------------------------------------------------------------------- /boa/interop/Neo/__init__.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | 3 | 4 | def to_script_hash(byte_array) -> bytes: 5 | """ 6 | Converts a data to a script hash. 7 | 8 | :param byte_array: data to hash. 9 | :type byte_array: bytearray or bytes 10 | 11 | :return: the script hash of the data 12 | :rtype: bytes 13 | """ 14 | intermed = hashlib.sha256(byte_array).digest() 15 | return hashlib.new('ripemd160', intermed).digest() 16 | 17 | 18 | def to_hex_str(data_bytes: bytes) -> str: 19 | """ 20 | Converts bytes into its string hex representation. 21 | 22 | :param data_bytes: data to represent as hex. 23 | :type data_bytes: bytearray or bytes 24 | 25 | :return: the hex representation of the data 26 | :rtype: str 27 | """ 28 | if isinstance(data_bytes, bytes): 29 | data_bytes = bytearray(data_bytes) 30 | data_bytes.reverse() 31 | return '0x' + data_bytes.hex() 32 | -------------------------------------------------------------------------------- /boa_test/example/SliceTest2.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Runtime import Notify 4 | from boa.builtins import concat 5 | 6 | 7 | def Main(): 8 | 9 | m = bytearray(b'\x01\x02\x03\x04\x05\x06\x07\x08') 10 | 11 | # this is a test to see if slice notation without specifying an end 12 | # is functional 13 | # s1 = m[2:] # it is not 14 | 15 | # without specifying beginning it is: 16 | s2 = m[:4] 17 | 18 | j = 2 19 | k = 4 20 | 21 | s3 = m[j:k] 22 | 23 | Notify(s3) 24 | 25 | s4 = m[get_slice_start():get_slice_end()] 26 | 27 | Notify(s4) 28 | 29 | ind = [1, 3, 4, 5] 30 | 31 | s6 = m[get_slice_start():ind[2]] 32 | 33 | Notify(s6) 34 | 35 | res = concat(s6, concat(s4, concat(s2, s3))) 36 | 37 | Notify(res) 38 | 39 | return res 40 | 41 | 42 | def get_slice_start(): 43 | 44 | return 1 45 | 46 | 47 | def get_slice_end(): 48 | return 6 49 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/SignatureTest.py: -------------------------------------------------------------------------------- 1 | from boa.builtins import verify_signature 2 | from boa.interop.Neo.Runtime import CheckWitness, Notify 3 | 4 | 5 | OWNER_PUBKEY = b'\x02\xf7\xbchi\xdf-\xbew\xa6bE\x11\x16\xcc\x99\x9cx\xc3^\xedA\xa11c\x17\xa3\xef\xe3c@t2' 6 | 7 | 8 | # this is the ScriptHash of the address that created the contract 9 | # the hex string is b'f223483e4287bd7c3e85a7ca896943179cbbc246' 10 | # the below is the hex version unhexxed and reversed 11 | 12 | OWNER_HASH = b'F\xc2\xbb\x9c\x17Ci\x89\xca\xa7\x85>|\xbd\x87B>H#\xf2' 13 | 14 | 15 | def Main(operation): 16 | 17 | verify = CheckWitness(OWNER_HASH) 18 | 19 | if verify: 20 | print("ok!!") 21 | else: 22 | print("not ok!") 23 | 24 | Notify(operation) 25 | 26 | # not sure of how this works 27 | verify2 = verify_signature(operation, OWNER_PUBKEY) 28 | 29 | Notify(verify2) # it returs false for now 30 | 31 | return True 32 | -------------------------------------------------------------------------------- /boa_test/example/demo/SerializationTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Runtime import Notify, Serialize, Deserialize 2 | from boa.interop.Neo.Storage import Put, Get, GetContext 3 | 4 | ctx = GetContext() 5 | 6 | 7 | def Main(operation): 8 | 9 | # create an array 10 | stuff = ['a', 3, ['j', 3, 5], 'jk', 'lmnopqr'] 11 | 12 | # serialize it 13 | to_save = Serialize(stuff) 14 | Put(ctx, 'serialized', to_save) 15 | 16 | if operation == 1: 17 | return to_save 18 | 19 | elif operation == 2: 20 | 21 | to_retrieve = Get(ctx, 'serialized') 22 | return to_retrieve 23 | 24 | elif operation == 3: 25 | 26 | to_retrieve = Get(ctx, 'serialized') 27 | deserialized = Deserialize(to_retrieve) 28 | return deserialized 29 | 30 | elif operation == 4: 31 | 32 | to_retrieve = Get(ctx, 'serialized') 33 | deserialized = Deserialize(to_retrieve) 34 | return deserialized[2] 35 | 36 | return False 37 | -------------------------------------------------------------------------------- /boa_test/example/BreakpointTest.py: -------------------------------------------------------------------------------- 1 | from boa.builtins import breakpoint 2 | from boa.interop.Neo.Blockchain import GetBlock 3 | from .demo.AnotherModule import another_module_method 4 | 5 | 6 | def Main(a): 7 | 8 | ret = False 9 | j = 12 10 | if a == 1: 11 | breakpoint() 12 | ret = True 13 | 14 | elif a == 2: 15 | ret = True 16 | breakpoint() 17 | 18 | elif a == 3: 19 | breakpoint() 20 | breakpoint() 21 | ret = True 22 | 23 | elif a == 4: 24 | 25 | j = 15 26 | breakpoint() 27 | 28 | elif a == 5: 29 | ret = another_method(6) 30 | 31 | elif a == 6: 32 | ret = another_module_method(3) 33 | 34 | elif a == 7: 35 | 36 | block = GetBlock(50424) 37 | 38 | breakpoint() 39 | 40 | ret = False 41 | 42 | return ret 43 | 44 | 45 | def another_method(q): 46 | 47 | h = q + 43 48 | 49 | m = h / 2 50 | 51 | breakpoint() 52 | 53 | return m 54 | -------------------------------------------------------------------------------- /boa_test/example/demo/Demo1.py: -------------------------------------------------------------------------------- 1 | 2 | from boa.builtins import concat 3 | 4 | 5 | def Main(operation, idx1, idx2): 6 | 7 | print("hello") 8 | 9 | # idx1 = 1 10 | # idx2 = 3 11 | 12 | mylist = [1, 2, 3, 5, 9, 1000, 32, -1] 13 | 14 | mystr_list = ['ab', 'bc', 'de', 'ef'] 15 | 16 | if operation == 'add': 17 | 18 | return mylist[idx1] + mylist[idx2] 19 | 20 | elif operation == 'sub': 21 | 22 | return mylist[idx1] - mylist[idx2] 23 | 24 | elif operation == 'fun': 25 | # my_method( 4, 6 ) == 10 26 | 27 | return my_method(my_method_2(mylist[idx1]), my_method_3(mylist[idx2])) 28 | 29 | # elif operation == 'concat_fun': 30 | 31 | # return concat(mystr_list[idx1], concat(mystr_list[idx2], concat(mystr_list[idx1]))) 32 | 33 | return False 34 | 35 | 36 | def my_method(a, b): 37 | 38 | return a + b 39 | 40 | 41 | def my_method_2(c): 42 | 43 | return c * 2 44 | 45 | 46 | def my_method_3(j): 47 | 48 | return j + 1 49 | -------------------------------------------------------------------------------- /boa_test/tests/test_verify_signature.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_verify_sig(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/VerifySignatureTest.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '', '01') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetBoolean(), True) 17 | 18 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '', '01') 19 | self.assertEqual(len(results), 1) 20 | self.assertEqual(results[0].GetBoolean(), False) 21 | 22 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '', '01') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBoolean(), False) 25 | -------------------------------------------------------------------------------- /boa_test/tests/test_slice.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_Slice1(self): 10 | output = Compiler.instance().load('%s/boa_test/example/SliceTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 13 | self.assertEqual(len(results), 1) 14 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x01\x02\x03\x04')) 15 | 16 | def test_Slice2(self): 17 | output = Compiler.instance().load('%s/boa_test/example/SliceTest2.py' % TestContract.dirname).default 18 | out = output.write() 19 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 20 | self.assertEqual(len(results), 1) 21 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x02\x03\x04\x02\x03\x04\x05\x06\x01\x02\x03\x04\x03\x04')) 22 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 Thomas Saunders and CoZ 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /boa_test/tests/test_compiler.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | import os 4 | 5 | 6 | class TestContract(BoaTest): 7 | 8 | TEST_SC_OUTPUT = 'boa_test/example/AddTest1.avm' 9 | 10 | @classmethod 11 | def setUpClass(cls): 12 | super(TestContract, cls).setUpClass() 13 | try: 14 | os.remove(cls.TEST_SC_OUTPUT) 15 | except Exception as e: 16 | pass 17 | 18 | def test_compile_1(self): 19 | 20 | try: 21 | sc = Compiler.load_and_save('%s/boa_test/example/AddTest1.py' % TestContract.dirname) 22 | 23 | expected_output = '%s/%s' % (TestContract.dirname, self.TEST_SC_OUTPUT) 24 | 25 | self.assertTrue(os.path.exists(expected_output)) 26 | except PermissionError: 27 | pass 28 | 29 | def test_compile_2(self): 30 | 31 | sc = Compiler.load('%s/boa_test/example/AddTest1.py' % TestContract.dirname) 32 | 33 | default_module = sc.default 34 | 35 | output = sc.write() 36 | 37 | self.assertIsInstance(output, bytes) 38 | 39 | self.assertTrue(len(output) > 0) 40 | -------------------------------------------------------------------------------- /docs/source/example/index.rst: -------------------------------------------------------------------------------- 1 | =================== 2 | Sample Python Files 3 | =================== 4 | 5 | The following is a selection of examples included with this project. The remainder of them can be seen at ``boa_test/examples``. All the following items as well as other tests are tested at ``boa_test/tests`` 6 | 7 | Addition 8 | ======== 9 | 10 | This example show how to add numbers. It is also an example of a smart contract that accepts multiple parameters (4). 11 | 12 | .. automodule:: boa_test.example.AddTest1 13 | :members: 14 | :undoc-members: 15 | 16 | Lists 17 | ===== 18 | 19 | This example shows how to create and manipulate lists. 20 | 21 | .. automodule:: boa_test.example.ArrayTest 22 | :members: 23 | :undoc-members: 24 | 25 | 26 | Binary Operators 27 | ================ 28 | 29 | This example shows how to use binary operators. 30 | 31 | .. automodule:: boa_test.example.BinopTest 32 | :members: 33 | :undoc-members: 34 | 35 | 36 | NEP5 Token 37 | ========== 38 | 39 | This example shows how to create a NEP5 token. 40 | 41 | .. automodule:: boa_test.example.demo.ICO_Template 42 | :members: 43 | :undoc-members: 44 | -------------------------------------------------------------------------------- /boa_test/example/VerifySignatureTest.py: -------------------------------------------------------------------------------- 1 | from boa.builtins import verify_signature 2 | 3 | 4 | def Main(operation): 5 | 6 | if operation == 1: 7 | 8 | # this should return true 9 | message = 'abcdef' 10 | signature = b'\xcd\x0c\xa9g\xd1\x1c\xeax\xe2Z\xd1o\x15\xdb\xe7vr%\x8b\xfe\xc5\x9f\xf3a|\x95\xe3\x17\xac\xff\x06:H\xd3_q\xaa\\\xe7\xd75\x97t\x12\x18n\x15rP}\x0fM L[\xcbl\x90\xe0;\x8b\x85\x7f\xbd' 11 | pubkey = b'\x03o\xbc\xb5\xe18\xc1\xceS`\xe8agL\x03"\x8a\xf75\xa9\x11J[\x7f\xb4\x12\x1b\x83P\x12\x9f?\xfe' 12 | 13 | result = verify_signature(pubkey, signature, message) 14 | 15 | return result 16 | 17 | elif operation == 2: 18 | # this should return false 19 | message = 'abcdefg' 20 | signature = b'\xcd\x0c\xa9g\xd1\x1c\xeax\xe2Z\xd1o\x15\xdb\xe7vr%\x8b\xfe\xc5\x9f\xf3a|\x95\xe3\x17\xac\xff\x06:H\xd3_q\xaa\\\xe7\xd75\x97t\x12\x18n\x15rP}\x0fM L[\xcbl\x90\xe0;\x8b\x85\x7f\xbd' 21 | pubkey = b'\x03o\xbc\xb5\xe18\xc1\xceS`\xe8agL\x03"\x8a\xf75\xa9\x11J[\x7f\xb4\x12\x1b\x83P\x12\x9f?\xfe' 22 | 23 | result = verify_signature(pubkey, signature, message) 24 | 25 | return result 26 | 27 | return False 28 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/BlockTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Blockchain import GetBlock 4 | from boa.interop.Neo.Block import * 5 | 6 | 7 | def Main(operation, height): 8 | 9 | block = GetBlock(height) 10 | 11 | if operation == 'get_hash': 12 | return block.Hash 13 | 14 | elif operation == 'get_index': 15 | return block.Index 16 | 17 | elif operation == 'get_timestamp': 18 | return block.Timestamp 19 | 20 | elif operation == 'get_prevhash': 21 | return block.PrevHash 22 | 23 | elif operation == 'get_version': 24 | return block.Version 25 | 26 | elif operation == 'get_nextconsensus': 27 | return block.NextConsensus 28 | 29 | elif operation == 'get_merkleroot': 30 | return block.MerkleRoot 31 | 32 | elif operation == 'get_consensusdata': 33 | return block.ConsensusData 34 | 35 | elif operation == 'get_transactioncount': 36 | return block.TransactionCount 37 | 38 | elif operation == 'get_transactions': 39 | return block.Transactions 40 | 41 | elif operation == 'get_transaction': 42 | return GetTransaction(block, 0) 43 | 44 | return 'unknown operation' 45 | -------------------------------------------------------------------------------- /boa_test/example/demo/IteratorTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Iterator import * 2 | 3 | 4 | def Main(testNum): 5 | 6 | items = { 7 | 'a': 1, 8 | 'c': 4, 9 | 'f': 13 10 | } 11 | 12 | vals = IterCreate(items) 13 | 14 | if testNum == 1: 15 | 16 | while IterNext(vals): 17 | 18 | print("next!") 19 | 20 | print("ok done") 21 | 22 | return True 23 | 24 | if testNum == 2: 25 | count = 0 26 | while next(vals): 27 | count += 1 28 | return count 29 | 30 | if testNum == 3: 31 | i = iter(items) 32 | keys = [] 33 | while next(i): 34 | keys.append(i.Key) 35 | 36 | return keys 37 | 38 | if testNum == 4: 39 | i = iter(items) 40 | values = [] 41 | while next(i): 42 | values.append(i.Value) 43 | 44 | return values 45 | 46 | if testNum == 5: 47 | count = 0 48 | while vals.next(): 49 | count += 1 50 | return count 51 | 52 | if testNum == 6: 53 | keys = [] 54 | while vals.Keys.next(): 55 | keys.append(vals.Value) 56 | return keys 57 | 58 | return False 59 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | =========================================== 2 | Python compiler for the Neo Virtual Machine 3 | =========================================== 4 | 5 | The ``neo-boa`` compiler is a tool for compiling Python files to the ``.avm`` format for usage in the `Neo Virtual Machine `_. The latter is used to execute contracts on the `Neo Blockchain `_. 6 | 7 | The compiler supports a subset of the Python language (in the same way that a Boa Contstrictor is a subset of the Python snake species.) 8 | 9 | 10 | .. toctree:: 11 | :maxdepth: 10 12 | 13 | overview 14 | install 15 | basicusage 16 | contribute 17 | license 18 | tests 19 | boa/compiler 20 | boa/code/module 21 | boa/code/method 22 | boa/code/expression 23 | boa/code/pytoken 24 | boa/code/vmtoken 25 | example/index 26 | boa/interop/blockchain 27 | boa/interop/executionengine 28 | 29 | 30 | .. _issue: https://github.com/CityOfZion/neo-boa/issues/new 31 | .. _NEO Slack: https://join.slack.com/t/neoblockchainteam/shared_invite/MjE3ODMxNDUzMDE1LTE1MDA4OTY3NDQtNTMwM2MyMTc2NA 32 | .. _MIT: https://github.com/CityOfZion/neo-python/blob/master/LICENSE.md -------------------------------------------------------------------------------- /boa_test/tests/test_many_elif.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | from neo.Settings import settings 7 | 8 | 9 | class TestContract(BoaTest): 10 | 11 | def test_ManyElif(self): 12 | 13 | output = Compiler.instance().load('%s/boa_test/example/TestManyElif.py' % TestContract.dirname).default 14 | out = output.write() 15 | 16 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '02') 17 | self.assertEqual(len(results), 1) 18 | self.assertEqual(results[0].GetBigInteger(), 2) 19 | 20 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', '02') 21 | self.assertEqual(len(results), 1) 22 | self.assertEqual(results[0].GetBigInteger(), 4) 23 | 24 | tx, results, total_ops, engine = TestBuild(out, [16], self.GetWallet1(), '02', '02') 25 | self.assertEqual(len(results), 1) 26 | self.assertEqual(results[0].GetBigInteger(), 17) 27 | 28 | tx, results, total_ops, engine = TestBuild(out, [22], self.GetWallet1(), '02', '02') 29 | self.assertEqual(len(results), 1) 30 | self.assertEqual(results[0].GetBigInteger(), -1) 31 | -------------------------------------------------------------------------------- /boa_test/tests/test_throw.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_Throw1(self): 10 | output = Compiler.instance().load('%s/boa_test/example/ThrowTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '07') 13 | self.assertEqual(len(results), 1) 14 | self.assertEqual(results[0].GetBoolean(), True) 15 | 16 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '07') 17 | self.assertEqual(len(results), 0) 18 | 19 | def test_Throw2(self): 20 | output = Compiler.instance().load('%s/boa_test/example/ThrowIfNotTest.py' % TestContract.dirname).default 21 | out = output.write() 22 | tx, results, total_ops, engine = TestBuild(out, [True], self.GetWallet1(), '01', '07') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBoolean(), True) 25 | 26 | tx, results, total_ops, engine = TestBuild(out, [False], self.GetWallet1(), '01', '07') 27 | self.assertEqual(len(results), 0) 28 | -------------------------------------------------------------------------------- /boa_test/example/TestManyElif.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def Main(operation): 4 | 5 | if operation == 1: 6 | return operation + 1 7 | 8 | elif operation == 2: 9 | return operation + 1 10 | 11 | elif operation == 3: 12 | return operation + 1 13 | 14 | elif operation == 4: 15 | return operation + 1 16 | 17 | elif operation == 5: 18 | return operation + 1 19 | 20 | elif operation == 6: 21 | return operation + 1 22 | 23 | elif operation == 7: 24 | return operation + 1 25 | 26 | elif operation == 8: 27 | return operation + 1 28 | 29 | elif operation == 9: 30 | return operation + 1 31 | 32 | elif operation == 10: 33 | return operation + 1 34 | 35 | elif operation == 11: 36 | return operation + 1 37 | 38 | elif operation == 12: 39 | return operation + 1 40 | 41 | elif operation == 13: 42 | return operation + 1 43 | 44 | elif operation == 14: 45 | return operation + 1 46 | 47 | elif operation == 15: 48 | return operation + 1 49 | 50 | elif operation == 16: 51 | return operation + 1 52 | 53 | elif operation == 17: 54 | return operation + 1 55 | 56 | elif operation == 18: 57 | return operation + 1 58 | 59 | return -1 60 | -------------------------------------------------------------------------------- /boa_test/example/CompareInTest.py: -------------------------------------------------------------------------------- 1 | 2 | def Main(operation): 3 | 4 | mylist = [1, 4, 10] 5 | 6 | q = b'\xab' 7 | 8 | myDict = { 9 | 'a': 1, 10 | 'b': 34, 11 | 'c': 'abc', 12 | q: '123' 13 | } 14 | 15 | if operation == 1: 16 | 17 | return 'a' in myDict 18 | 19 | elif operation == 2: 20 | 21 | return 3 in myDict 22 | 23 | elif operation == 3: 24 | 25 | # this should return true 26 | # the neo-vm uses 'HAS_KEY' op for lists 27 | # which only checks the length of the array :( 28 | # it doesn't test whether the array 29 | # contains the value 30 | return 2 in mylist 31 | 32 | elif operation == 4: 33 | # this should return false 34 | # even though 10 is in the list 35 | # because the list isn't 10 items long 36 | return 10 in mylist 37 | 38 | elif operation == 5: 39 | 40 | myDict['h'] = 3 41 | 42 | return 'h' in myDict 43 | 44 | elif operation == 6: 45 | 46 | mylist.append(8) 47 | 48 | return 3 in mylist 49 | 50 | elif operation == 7: 51 | 52 | myDict[7] = 'a' 53 | 54 | return 7 in myDict 55 | 56 | elif operation == 8: 57 | 58 | myDict.remove('a') 59 | 60 | return 'a' in myDict 61 | 62 | elif operation == 9: 63 | 64 | return b'\xab' in myDict 65 | 66 | return False 67 | -------------------------------------------------------------------------------- /boa_test/example/demo/EnumeratorTest.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Enumerator import * 2 | 3 | 4 | def Main(testNum): 5 | 6 | items = [1, 2, 3, 5, 9, 14] 7 | 8 | vals = EnumeratorCreate(items) 9 | 10 | if testNum == 1: 11 | 12 | while EnumeratorNext(vals): 13 | 14 | print("next!") 15 | 16 | print("ok done") 17 | 18 | return True 19 | 20 | if testNum == 2: 21 | 22 | ret = [] 23 | while EnumeratorNext(vals): 24 | ret.append(vals.Value) 25 | 26 | return ret 27 | 28 | if testNum == 3: 29 | ret = [] 30 | vals = enumerate(items) 31 | 32 | while EnumeratorNext(vals): 33 | ret.append(vals.Value) 34 | 35 | return ret 36 | 37 | if testNum == 4: 38 | 39 | items2 = ['a', 'b', 'd', 'f'] 40 | 41 | enum2 = EnumeratorCreate(items2) 42 | 43 | doublenumerator = EnumeratorConcat(vals, enum2) 44 | 45 | ret = [] 46 | 47 | while EnumeratorNext(doublenumerator): 48 | ret.append(doublenumerator.Value) 49 | return ret 50 | 51 | if testNum == 5: 52 | 53 | count = 0 54 | while next(vals): 55 | count += 1 56 | return count 57 | 58 | if testNum == 6: 59 | 60 | myenum = enumerate(items) 61 | count = 0 62 | while myenum.next(): 63 | count += 1 64 | return count 65 | 66 | return False 67 | -------------------------------------------------------------------------------- /boa_test/tests/test_bytearray.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_BA1(self): 10 | output = Compiler.instance().load('%s/boa_test/example/ByteArrayTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 13 | self.assertEqual(len(results), 1) 14 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\t\x01\x02\xaf\t')) 15 | 16 | def test_BA2(self): 17 | output = Compiler.instance().load('%s/boa_test/example/ByteArrayTest2.py' % TestContract.dirname).default 18 | out = output.write() 19 | tx, results, total_ops, engine = TestBuild(out, [bytearray(b'abcefghi'), bytearray(b'zyxwvutrs')], self.GetWallet1(), '0505', '05') 20 | self.assertEqual(len(results), 1) 21 | self.assertEqual(results[0].GetByteArray(), bytearray(b'bcefghistaoheustnauzyxwvutrs')) 22 | 23 | def test_BA3(self): 24 | output = Compiler.instance().load('%s/boa_test/example/ByteArrayTest3.py' % TestContract.dirname).default 25 | out = output.write() 26 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '05') 27 | self.assertEqual(len(results), 1) 28 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x01\x02\xaa\xfe')) 29 | -------------------------------------------------------------------------------- /boa_test/example/demo/token/txio.py: -------------------------------------------------------------------------------- 1 | from boa.interop.System.ExecutionEngine import GetScriptContainer, GetExecutingScriptHash 2 | from boa.interop.Neo.Transaction import Transaction, GetReferences, GetOutputs, GetUnspentCoins 3 | from boa.interop.Neo.Output import GetValue, GetAssetId, GetScriptHash 4 | 5 | 6 | neo_asset_id = b'\x9b|\xff\xda\xa6t\xbe\xae\x0f\x93\x0e\xbe`\x85\xaf\x90\x93\xe5\xfeV\xb3J\\"\x0c\xcd\xcfn\xfc3o\xc5' 7 | 8 | gas_asset_id = b'\xe7-(iy\xeel\xb1\xb7\xe6]\xfd\xdf\xb2\xe3\x84\x10\x0b\x8d\x14\x8ewX\xdeB\xe4\x16\x8bqy,`' 9 | 10 | 11 | def get_asset_attachments(): 12 | """ 13 | Gets information about NEO and Gas attached to an invocation TX 14 | 15 | :return: 16 | list: A list with information about attached neo and gas 17 | """ 18 | 19 | tx = GetScriptContainer() 20 | references = tx.References 21 | 22 | receiver_addr = GetExecutingScriptHash() 23 | sender_addr = None 24 | sent_amount_neo = 0 25 | sent_amount_gas = 0 26 | 27 | if len(references) > 0: 28 | 29 | reference = references[0] 30 | sender_addr = reference.ScriptHash 31 | for output in tx.Outputs: 32 | if output.ScriptHash == receiver_addr: 33 | if output.AssetId == neo_asset_id: 34 | sent_amount_neo += output.Value 35 | if output.AssetId == gas_asset_id: 36 | sent_amount_gas += output.Value 37 | 38 | return [receiver_addr, sender_addr, sent_amount_neo, sent_amount_gas] 39 | -------------------------------------------------------------------------------- /docs/source/boa/interop/blockchain.rst: -------------------------------------------------------------------------------- 1 | ======================== 2 | [Interop] Neo Blockchain 3 | ======================== 4 | 5 | The items below are used for gathering state data contained within the blockchain. 6 | Because all items below are implemented in the Neo Virtual Machine, their source is not available here. 7 | Please see the `neo-python `_ project if you want to know more about their exact implementation. 8 | 9 | 10 | Blockchain 11 | ^^^^^^^^^^ 12 | 13 | .. automodule:: boa.interop.Neo.Blockchain 14 | 15 | 16 | Header 17 | ^^^^^^ 18 | A Header object contains all information about a block, except for the transaction data. 19 | 20 | .. automodule:: boa.interop.Neo.Header 21 | 22 | 23 | Block 24 | ^^^^^ 25 | 26 | A Block object contains the transaction data for a block. 27 | 28 | .. automodule:: boa.interop.Neo.Block 29 | 30 | 31 | Account 32 | ^^^^^^^ 33 | 34 | The Account object represents an address on the blockchain. 35 | 36 | .. automodule:: boa.interop.Neo.Account 37 | 38 | 39 | Action 40 | ^^^^^^ 41 | 42 | An Action object is used to register an action/event listener on the blockchain. 43 | 44 | .. automodule:: boa.interop.Neo.Action 45 | 46 | 47 | App 48 | ^^^ 49 | 50 | An App object used to call other contracts on the blockchain. 51 | 52 | .. automodule:: boa.interop.Neo.App 53 | 54 | 55 | Asset 56 | ^^^^^ 57 | 58 | An Asset object is used to look up information about native assets such as NEO or Gas. 59 | 60 | .. automodule:: boa.interop.Neo.Asset 61 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/TransactionTypeTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.TransactionType import * 4 | 5 | 6 | def Main(operation): 7 | """ 8 | MinerTransaction = b'\x00' 9 | IssueTransaction = b'\x01' 10 | ClaimTransaction = b'\x02' 11 | EnrollmentTransaction = b'\x20' 12 | VotingTransaction = b'\x24' 13 | RegisterTransaction = b'\x40' 14 | ContractTransaction = b'\x80' 15 | StateTransaction = b'\x90' 16 | AgencyTransaction = b'\xb0' 17 | PublishTransaction = b'\xd0' 18 | InvocationTransaction = b'\xd1' 19 | """ 20 | 21 | if operation == 'miner': 22 | return MinerTransaction() 23 | 24 | elif operation == 'issue': 25 | return IssueTransaction() 26 | 27 | elif operation == 'claim': 28 | return ClaimTransaction() 29 | 30 | elif operation == 'enrollment': 31 | return EnrollmentTransaction() 32 | 33 | elif operation == 'voting': 34 | return VotingTransaction() 35 | 36 | elif operation == 'register': 37 | return RegisterTransaction() 38 | 39 | elif operation == 'contract': 40 | return ContractTransaction() 41 | 42 | elif operation == 'state': 43 | return StateTransaction() 44 | 45 | elif operation == 'agency': 46 | return AgencyTransaction() 47 | 48 | elif operation == 'publish': 49 | return PublishTransaction() 50 | 51 | elif operation == 'invocation': 52 | return InvocationTransaction() 53 | 54 | return 'unknown operation' 55 | -------------------------------------------------------------------------------- /boa_test/tests/test_dict.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Settings import settings 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_dict1(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/DictTest1.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 15 | self.assertEqual(len(results), 1) 16 | self.assertIsInstance(results[0].GetMap(), dict) 17 | self.assertEqual(results[0].GetBoolean(), True) 18 | 19 | def test_dict2(self): 20 | 21 | output = Compiler.instance().load('%s/boa_test/example/DictTest2.py' % TestContract.dirname).default 22 | out = output.write() 23 | 24 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 25 | self.assertEqual(len(results), 1) 26 | self.assertEqual(results[0].GetBigInteger(), 7) 27 | 28 | def test_dict3(self): 29 | 30 | output = Compiler.instance().load('%s/boa_test/example/DictTest3.py' % TestContract.dirname).default 31 | out = output.write() 32 | string_ouput = output.to_s() 33 | self.assertGreater(len(string_ouput), 0) 34 | 35 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 36 | self.assertEqual(len(results), 1) 37 | self.assertIsInstance(results[0].GetMap(), dict) 38 | -------------------------------------------------------------------------------- /boa/interop/System/ExecutionEngine.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | def GetScriptContainer(): 4 | """ 5 | Return the current Script Container of a smart contract execution. 6 | This will be a ``boa.blockchain.vm.Neo.Transaction`` object. 7 | 8 | - Note: This method is implemented inside the Neo Virtual Machine. 9 | 10 | :return: the current ScriptContainer of a smart contract execution. 11 | :rtype: ``boa.blockchain.vm.Neo.Transaction`` 12 | """ 13 | 14 | pass 15 | 16 | 17 | def GetExecutingScriptHash(): 18 | """ 19 | Get the hash of the script ( smart contract ) which is currently being executed 20 | 21 | - Note: This method is implemented inside the Neo Virtual Machine. 22 | 23 | :return: the hash of the script ( smart contract ) which is currently being executed 24 | :rtype: bytearray 25 | """ 26 | 27 | pass 28 | 29 | 30 | def GetCallingScriptHash(): 31 | """ 32 | Get the hash of the script ( smart contract ) which began execution of the current script. 33 | 34 | - Note: This method is implemented inside the Neo Virtual Machine. 35 | 36 | :return: the hash of the script ( smart contract ) which began execution of the current script 37 | :rtype: bytearray 38 | """ 39 | 40 | pass 41 | 42 | 43 | def GetEntryScriptHash(): 44 | """ 45 | Get the hash of the script ( smart contract ) which began execution of the smart contract. 46 | 47 | - Note: This method is implemented inside the Neo Virtual Machine. 48 | 49 | :return: the hash of the script ( smart contract ) which began execution of the smart contract 50 | :rtype: bytearray 51 | """ 52 | 53 | pass 54 | -------------------------------------------------------------------------------- /boa/util.py: -------------------------------------------------------------------------------- 1 | from bytecode import UNSET, Label, Instr, Bytecode, BasicBlock, ControlFlowGraph 2 | from boa.code import pyop 3 | import glob 4 | import importlib 5 | 6 | 7 | class BlockType(): 8 | MAKE_FUNCTION = 0 9 | CALL_FUNCTION = 1 10 | MAKE_CLASS = 2 11 | IMPORT_ITEM = 3 12 | MODULE_VAR = 4 13 | DOC_STRING = 5 14 | LOAD_CONST = 6 15 | ACTION_REG = 7 16 | APPCALL_REG = 8 17 | UNKNOWN = 9 18 | 19 | 20 | def get_block_type(block): 21 | default = BlockType.UNKNOWN 22 | for instr in block: 23 | if instr.opcode == pyop.LOAD_NAME and instr.arg == 'RegisterAction': 24 | if default != BlockType.UNKNOWN: 25 | return default 26 | return BlockType.ACTION_REG 27 | elif instr.opcode == pyop.LOAD_NAME and instr.arg == 'RegisterAppCall': 28 | if default != BlockType.UNKNOWN: 29 | return default 30 | return BlockType.APPCALL_REG 31 | elif instr.opcode in [pyop.IMPORT_FROM, pyop.IMPORT_NAME, pyop.IMPORT_STAR]: 32 | if default != BlockType.UNKNOWN: 33 | return default 34 | return BlockType.IMPORT_ITEM 35 | elif instr.opcode == pyop.MAKE_FUNCTION: 36 | return BlockType.MAKE_FUNCTION 37 | elif instr.opcode == pyop.LOAD_BUILD_CLASS: 38 | if default != BlockType.UNKNOWN: 39 | return default 40 | return BlockType.MAKE_CLASS 41 | elif instr.opcode == pyop.CALL_FUNCTION: 42 | if default != BlockType.UNKNOWN: 43 | return default 44 | default = BlockType.CALL_FUNCTION 45 | 46 | return default 47 | -------------------------------------------------------------------------------- /boa/interop/Neo/Contract.py: -------------------------------------------------------------------------------- 1 | 2 | class Contract: 3 | 4 | @property 5 | def Script(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetScript(self) 11 | 12 | @property 13 | def StorageContext(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetStorageContext(self) 19 | 20 | @property 21 | def IsPayable(self): 22 | """ 23 | 24 | :return: 25 | """ 26 | return GetIsPayable(self) 27 | 28 | 29 | def GetScript(contract): 30 | """ 31 | 32 | :param contract: 33 | """ 34 | pass 35 | 36 | 37 | def GetStorageContext(contract): 38 | """ 39 | 40 | :param contract: 41 | """ 42 | pass 43 | 44 | 45 | def GetIsPayable(contract): 46 | """ 47 | 48 | :param contract: 49 | """ 50 | pass 51 | 52 | 53 | def Create(script, parameter_list, return_type, properties, name, version, author, email, description): 54 | """ 55 | 56 | :param script: 57 | :param parameter_list: 58 | :param return_type: 59 | :param properties: 60 | :param name 61 | :param version: 62 | :param author: 63 | :param email: 64 | :param description: 65 | """ 66 | pass 67 | 68 | 69 | def Migrate(script, parameter_list, return_type, properties, name, version, author, email, description): 70 | """ 71 | 72 | :param script: 73 | :param parameter_list: 74 | :param return_type: 75 | :param need_storage: 76 | :param name 77 | :param version: 78 | :param author: 79 | :param email: 80 | :param description: 81 | """ 82 | pass 83 | 84 | 85 | def Destroy(): 86 | """ 87 | 88 | :param contract: 89 | """ 90 | pass 91 | -------------------------------------------------------------------------------- /boa_test/tests/test_system.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaFixtureTest 2 | from boa.compiler import Compiler 3 | from neo.Core.TX.Transaction import Transaction 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaFixtureTest): 8 | 9 | def test_Runtime(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/blockchain/ExecutionEngineTest.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, ['executing_sh'], self.GetWallet1(), '07', '05') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x82\x13\x19\xd7\xfc\x87\xec\xa5\xae\x04\x91\xf60E\xd5\xac\x9a\x07\xe2\xb1')) 17 | 18 | tx, results, total_ops, engine = TestBuild(out, ['calling_sh'], self.GetWallet1(), '07', '05') 19 | self.assertEqual(len(results), 1) 20 | print("results: %s " % results[0].GetByteArray()) 21 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xb6\xa9\xdf\xfe\x85o\xdb<\x04\x7f\xacW\xc6\xc1)\xdb\xc5|\x12\xaa')) 22 | 23 | tx, results, total_ops, engine = TestBuild(out, ['entry_sh'], self.GetWallet1(), '07', '05') 24 | self.assertEqual(len(results), 1) 25 | self.assertEqual(results[0].GetByteArray(), bytearray(b'2\xdez&\xc4\xc2>\xcbQ0\xa3cJ\x8c\xbdjd\xe9\x8d\xed')) 26 | 27 | tx, results, total_ops, engine = TestBuild(out, ['script_container'], self.GetWallet1(), '07', '05') 28 | self.assertEqual(len(results), 1) 29 | self.assertEqual(len(results), 1) 30 | res = results[0].GetInterface() 31 | self.assertIsInstance(res, Transaction) 32 | self.assertEqual(res, tx) 33 | -------------------------------------------------------------------------------- /boa_test/tests/test_event.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | from neo.EventHub import events, SmartContractEvent 6 | 7 | 8 | class TestContract(BoaTest): 9 | 10 | def test_Event1(self): 11 | 12 | dispatched_events = [] 13 | 14 | def on_notif(evt): 15 | dispatched_events.append(evt) 16 | events.on(SmartContractEvent.RUNTIME_NOTIFY, on_notif) 17 | 18 | output = Compiler.instance().load('%s/boa_test/example/blockchain/EventTest.py' % TestContract.dirname).default 19 | out = output.write() 20 | 21 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 22 | self.assertEqual(len(results), 1) 23 | 24 | self.assertEqual(results[0].GetBigInteger(), 7) 25 | 26 | events.off(SmartContractEvent.RUNTIME_NOTIFY, on_notif) 27 | 28 | self.assertEqual(len(dispatched_events), 2) 29 | 30 | transfer_event_payload = dispatched_events[0].event_payload 31 | 32 | payload = transfer_event_payload.Value 33 | self.assertEqual(len(payload), 4) 34 | self.assertEqual(payload[0].Value, b'transfer_test') 35 | self.assertEqual(payload[1].Value, '2') 36 | self.assertEqual(payload[2].Value, '5') 37 | self.assertEqual(payload[3].Value, '7') 38 | 39 | refund_event_payload = dispatched_events[1].event_payload.Value 40 | self.assertEqual(len(refund_event_payload), 3) 41 | self.assertEqual(refund_event_payload[0].Value, b'refund') 42 | self.assertEqual(refund_event_payload[1].Value, b'me') 43 | self.assertEqual(int.from_bytes(refund_event_payload[2].Value, 'little'), 52) 44 | -------------------------------------------------------------------------------- /boa_test/tests/test_module_vars.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_M1(self): 10 | output = Compiler.instance().load('%s/boa_test/example/ModuleVariableTest1.py' % TestContract.dirname).default 11 | out = output.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBigInteger(), 8) 16 | 17 | def test_M2(self): 18 | output = Compiler.instance().load('%s/boa_test/example/ModuleVariableTest.py' % TestContract.dirname).default 19 | out = output.write() 20 | 21 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetBigInteger(), 1260) 24 | 25 | def test_M3(self): 26 | output = Compiler.instance().load('%s/boa_test/example/ModuleMethodTest1.py' % TestContract.dirname).default 27 | out = output.write() 28 | 29 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBoolean(), True) 32 | 33 | def test_M4(self): 34 | output = Compiler.instance().load('%s/boa_test/example/ModuleMethodTest2.py' % TestContract.dirname).default 35 | out = output.write() 36 | 37 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 38 | self.assertEqual(len(results), 1) 39 | self.assertEqual(results[0].GetBigInteger(), 3003) 40 | -------------------------------------------------------------------------------- /boa_test/tests/test_equality.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Prompt.Commands.BuildNRun import TestBuild 4 | 5 | 6 | class TestContract(BoaTest): 7 | 8 | def test_Equality(self): 9 | 10 | output = Compiler.instance().load('%s/boa_test/example/EqualityTest2.py' % TestContract.dirname).default 11 | out = output.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '', '07') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBoolean(), False) 16 | 17 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '', '07') 18 | self.assertEqual(len(results), 1) 19 | self.assertEqual(results[0].GetBoolean(), True) 20 | 21 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '', '07') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetBoolean(), True) 24 | 25 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '', '07') 26 | self.assertEqual(len(results), 1) 27 | self.assertEqual(results[0].GetBoolean(), True) 28 | 29 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '', '07') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBoolean(), True) 32 | 33 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '', '07') 34 | self.assertEqual(len(results), 1) 35 | self.assertEqual(results[0].GetBoolean(), True) 36 | 37 | tx, results, total_ops, engine = TestBuild(out, [7], self.GetWallet1(), '', '07') 38 | self.assertEqual(len(results), 1) 39 | self.assertEqual(results[0].GetBoolean(), False) 40 | -------------------------------------------------------------------------------- /boa_test/tests/test_account.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaFixtureTest 2 | from boa.compiler import Compiler 3 | from neo.Core.TX.Transaction import Transaction 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaFixtureTest): 8 | 9 | def test_Account(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/blockchain/AccountTest.py' % TestContract.dirname).default 12 | out = output.write() 13 | string_ouput = output.to_s() 14 | self.assertGreater(len(string_ouput), 0) 15 | 16 | account = self.wallet_1_script_hash.Data 17 | 18 | bad_account = bytearray(b'S\xefB\xc8\xdf!^\xbeZ|z\xe8\x01\xcb\xc3\xac/\xacE)') 19 | 20 | tx, results, total_ops, engine = TestBuild(out, ['get_hash', bad_account], self.GetWallet1(), '07', '05') 21 | self.assertEqual(len(results), 1) 22 | self.assertEqual(results[0].GetBoolean(), True) 23 | 24 | tx, results, total_ops, engine = TestBuild(out, ['get_hash', account], self.GetWallet1(), '07', '05') 25 | self.assertEqual(len(results), 1) 26 | self.assertEqual(results[0].GetByteArray(), account) 27 | 28 | tx, results, total_ops, engine = TestBuild(out, ['get_votes', account], self.GetWallet1(), '07', '05') 29 | self.assertEqual(len(results), 1) 30 | self.assertEqual(results[0].GetArray(), []) 31 | 32 | tx, results, total_ops, engine = TestBuild(out, ['get_balance_gas', account], self.GetWallet1(), '07', '05') 33 | self.assertEqual(len(results), 1) 34 | self.assertEqual(results[0].GetBigInteger(), 1399980000) 35 | 36 | tx, results, total_ops, engine = TestBuild(out, ['get_balance_neo', account], self.GetWallet1(), '07', '05') 37 | self.assertEqual(len(results), 1) 38 | self.assertEqual(results[0].GetBigInteger(), 5000000000) 39 | -------------------------------------------------------------------------------- /boa/code/appcall.py: -------------------------------------------------------------------------------- 1 | import pdb 2 | import binascii 3 | from boa.code import pyop 4 | 5 | 6 | class appcall(): 7 | 8 | script_hash = None 9 | script_args = None 10 | 11 | method_name = None 12 | 13 | def __init__(self, block): 14 | 15 | arguments = [] 16 | 17 | for i, item in enumerate(block): 18 | if item.opcode == pyop.LOAD_CONST: 19 | arguments.append(item.arg) 20 | elif item.opcode == pyop.STORE_NAME: 21 | self.method_name = item.arg 22 | 23 | self.script_hash = arguments[0] 24 | 25 | self.script_args = arguments 26 | 27 | if type(self.script_hash) is str: 28 | if len(self.script_hash) != 40: 29 | raise Exception( 30 | "Invalid script hash! length of string must be 40") 31 | elif type(self.script_hash) in [bytes, bytearray]: 32 | if len(self.script_hash) != 20: 33 | raise Exception( 34 | "Invalid Script hash, length in bytes must be 20") 35 | else: 36 | raise Exception( 37 | "Invalid script hash type. must be string, bytes, or bytearray") 38 | 39 | @property 40 | def script_hash_addr(self): 41 | """ 42 | 43 | :return: 44 | """ 45 | 46 | return appcall.to_script_hash_data(self.script_hash) 47 | 48 | @staticmethod 49 | def to_script_hash_data(item): 50 | """ 51 | 52 | :return: 53 | """ 54 | b_array = None 55 | if type(item) is str: 56 | bstring = item.encode('utf-8') 57 | b_array = bytearray(binascii.unhexlify(bstring)) 58 | elif type(item) is bytearray: 59 | pass 60 | elif type(item) is bytes: 61 | b_array = bytearray(item) 62 | else: 63 | raise Exception("Invalid script hash") 64 | 65 | b_array.reverse() 66 | 67 | return bytes(b_array) 68 | -------------------------------------------------------------------------------- /boa/code/ast_preprocess.py: -------------------------------------------------------------------------------- 1 | from bytecode import Bytecode 2 | import ast 3 | from ast import NodeTransformer, NodeVisitor 4 | import inspect 5 | import pdb 6 | import dis 7 | 8 | 9 | class RewriteDicts(NodeTransformer): 10 | 11 | last_store_name = None 12 | 13 | updated_dicts = [] 14 | 15 | def visit_Dict(self, node): 16 | if len(node.keys): 17 | 18 | if self.last_store_name and self.last_store_name.id and self.last_store_name.lineno == node.lineno: 19 | for item in node.values: 20 | if isinstance(item, ast.Dict): 21 | raise Exception("Cannot use dictionaries inside of dictionaries") 22 | 23 | node.name = self.last_store_name.id 24 | self.updated_dicts.append(node) 25 | self.last_store_name = None 26 | else: 27 | raise Exception("Dictionary names must be declared") 28 | 29 | return ast.Dict(keys=[], values=[], lineno=node.lineno) 30 | 31 | def visit_Name(self, node): 32 | if isinstance(node.ctx, ast.Store): 33 | self.last_store_name = node 34 | else: 35 | self.last_store_name = None 36 | return node 37 | 38 | 39 | def preprocess_method_body(source_code_obj): 40 | 41 | src = inspect.getsource(source_code_obj) 42 | 43 | ast_tree = ast.parse(src) 44 | 45 | visitor = RewriteDicts() 46 | ast_tree = visitor.visit(ast_tree) 47 | 48 | ast.fix_missing_locations(ast_tree) 49 | updated_code = compile(ast_tree, filename='', mode='exec') 50 | bc = Bytecode.from_code(updated_code) 51 | 52 | dlist = visitor.updated_dicts 53 | RewriteDicts.updated_dicts = [] 54 | RewriteDicts.last_store_name = None 55 | 56 | block_code = get_code_block(bc) 57 | return block_code.arg, dlist 58 | 59 | 60 | def get_code_block(blocks): 61 | for block in blocks: 62 | if inspect.iscode(block.arg): 63 | return block 64 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build_deploy: &build_deploy 4 | working_directory: ~/neo-boa 5 | docker: 6 | - image: circleci/python:3.6.4 7 | steps: 8 | - checkout 9 | 10 | - run: 11 | name: Setup Environment 12 | command: | 13 | python3 -m venv venv 14 | source venv/bin/activate 15 | 16 | - run: 17 | name: Install Deps 18 | command: | 19 | sudo pip install -r requirements_dev.txt 20 | 21 | - run: 22 | name: Build .pypirc 23 | command: | 24 | echo -e "[$PYPI_REPO]" >> ~/.pypirc 25 | echo -e "username = $PYPI_USERNAME" >> ~/.pypirc 26 | echo -e "password = $PYPI_PASSWORD" >> ~/.pypirc 27 | 28 | - run: 29 | name: Verify Package Name 30 | command: | 31 | [[ $PYPI_REPO = testpypi ]] && sed -i "s/name='neo-boa'/name='neo-boa-test'/g" setup.py 32 | true 33 | - run: 34 | name: Build Package 35 | command: | 36 | python3 setup.py sdist bdist_wheel 37 | 38 | - run: 39 | name: Push to TestPyPi 40 | command: 41 | python3 -m twine upload --repository $PYPI_REPO dist/* 42 | build_deploy_test: 43 | <<: *build_deploy 44 | build_deploy_prod: 45 | <<: *build_deploy 46 | 47 | 48 | workflows: 49 | version: 2 50 | build_deploy: 51 | jobs: 52 | - build_deploy_test: 53 | context: pypi_test 54 | filters: 55 | tags: 56 | only: /^v.*/ 57 | branches: 58 | ignore: /.*/ 59 | - approve-release: 60 | type: approval 61 | requires: 62 | - build_deploy_test 63 | filters: 64 | tags: 65 | only: /^v.*/ 66 | branches: 67 | ignore: /.*/ 68 | - build_deploy_prod: 69 | context: pypi_prod 70 | requires: 71 | - approve-release 72 | filters: 73 | tags: 74 | only: /^v.*/ 75 | branches: 76 | ignore: /.*/ -------------------------------------------------------------------------------- /boa_test/tests/test_compare_in.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_compare_in(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/CompareInTest.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '', '01') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetBoolean(), True) 17 | 18 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '', '01') 19 | self.assertEqual(len(results), 1) 20 | self.assertEqual(results[0].GetBoolean(), False) 21 | 22 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '', '01') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBoolean(), True) 25 | 26 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '', '01') 27 | self.assertEqual(len(results), 1) 28 | self.assertEqual(results[0].GetBoolean(), False) 29 | 30 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '', '01') 31 | self.assertEqual(len(results), 1) 32 | self.assertEqual(results[0].GetBoolean(), True) 33 | 34 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '', '01') 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetBoolean(), True) 37 | 38 | tx, results, total_ops, engine = TestBuild(out, [7], self.GetWallet1(), '', '01') 39 | self.assertEqual(len(results), 1) 40 | self.assertEqual(results[0].GetBoolean(), True) 41 | 42 | tx, results, total_ops, engine = TestBuild(out, [8], self.GetWallet1(), '', '01') 43 | self.assertEqual(len(results), 1) 44 | self.assertEqual(results[0].GetBoolean(), False) 45 | 46 | tx, results, total_ops, engine = TestBuild(out, [9], self.GetWallet1(), '', '01') 47 | self.assertEqual(len(results), 1) 48 | self.assertEqual(results[0].GetBoolean(), True) 49 | -------------------------------------------------------------------------------- /boa_test/tests/test_dict_create.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Settings import settings 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_dict1(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/DictTest4.py' % TestContract.dirname).default 12 | out = output.write() 13 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBigInteger(), 10) 16 | 17 | def test_dict2(self): 18 | 19 | with self.assertRaises(Exception) as ctx: 20 | Compiler.instance().load('%s/boa_test/example/DictTest5_ShouldNotCompile.py' % TestContract.dirname).default.write() 21 | 22 | def test_dict3(self): 23 | 24 | with self.assertRaises(Exception) as ctx: 25 | Compiler.instance().load('%s/boa_test/example/DictTest6_ShouldNotCompile.py' % TestContract.dirname).default.write() 26 | 27 | def test_dict_keys1(self): 28 | output = Compiler.instance().load('%s/boa_test/example/DictTestKeys.py' % TestContract.dirname).default 29 | out = output.write() 30 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 31 | self.assertEqual(len(results), 1) 32 | self.assertEqual(results[0].GetByteArray(), bytearray(b'ab\x04mzmcallltrs')) 33 | 34 | def test_dict_values1(self): 35 | output = Compiler.instance().load('%s/boa_test/example/DictTestValues.py' % TestContract.dirname).default 36 | out = output.write() 37 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 38 | self.assertEqual(len(results), 1) 39 | self.assertEqual(results[0].GetBigInteger(), 55) 40 | 41 | def test_dict_has_key(self): 42 | output = Compiler.instance().load('%s/boa_test/example/DictTestHasKey.py' % TestContract.dirname).default 43 | out = output.write() 44 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 45 | self.assertEqual(len(results), 1) 46 | self.assertEqual(results[0].GetBigInteger(), 22) 47 | -------------------------------------------------------------------------------- /boa/interop/Neo/Transaction.py: -------------------------------------------------------------------------------- 1 | 2 | class Transaction: 3 | 4 | @property 5 | def Hash(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetTXHash(self) 11 | 12 | @property 13 | def Type(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetType(self) 19 | 20 | @property 21 | def Attributes(self): 22 | """ 23 | 24 | :return: 25 | """ 26 | return GetAttributes(self) 27 | 28 | @property 29 | def Inputs(self): 30 | """ 31 | 32 | :return: 33 | """ 34 | return GetInputs(self) 35 | 36 | @property 37 | def Outputs(self): 38 | """ 39 | 40 | :return: 41 | """ 42 | return GetOutputs(self) 43 | 44 | @property 45 | def References(self): 46 | """ 47 | 48 | :return: 49 | """ 50 | return GetReferences(self) 51 | 52 | @property 53 | def UnspentCoins(self): 54 | return GetUnspentCoins(self) 55 | 56 | @property 57 | def Witnesses(self): 58 | return GetWitnesses(self) 59 | 60 | 61 | def GetTXHash(transaction): 62 | """ 63 | 64 | :param transaction: 65 | """ 66 | pass 67 | 68 | 69 | def GetType(transaction): 70 | """ 71 | 72 | :param transaction: 73 | """ 74 | pass 75 | 76 | 77 | def GetAttributes(transaction): 78 | """ 79 | 80 | :param transaction: 81 | """ 82 | pass 83 | 84 | 85 | def GetInputs(transaction): 86 | """ 87 | 88 | :param transaction: 89 | """ 90 | pass 91 | 92 | 93 | def GetOutputs(transaction): 94 | """ 95 | 96 | :param transaction: 97 | """ 98 | pass 99 | 100 | 101 | def GetReferences(transaction): 102 | """ 103 | 104 | :param transaction: 105 | """ 106 | pass 107 | 108 | 109 | def GetUnspentCoins(transaction): 110 | """ 111 | 112 | Args: 113 | transaction: 114 | 115 | Returns: 116 | 117 | """ 118 | pass 119 | 120 | 121 | def GetWitnesses(transaction): 122 | """ 123 | 124 | Args: 125 | transaction: 126 | 127 | Returns: 128 | 129 | """ 130 | pass 131 | -------------------------------------------------------------------------------- /boa_test/tests/test_storage_find.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Settings import settings 4 | 5 | settings.USE_DEBUG_STORAGE = True 6 | settings.DEBUG_STORAGE_PATH = './fixtures/debugstorage' 7 | 8 | from neo.Prompt.Commands.BuildNRun import TestBuild 9 | 10 | 11 | class TestContract(BoaTest): 12 | 13 | def test_storage_find(self): 14 | 15 | output = Compiler.instance().load('%s/boa_test/example/blockchain/StorageFindTest.py' % TestContract.dirname).default 16 | out = output.write() 17 | 18 | tx, results, total_ops, engine = TestBuild(out, ['prefix'], self.GetWallet1(), '', '10') 19 | self.assertEqual(len(results), 1) 20 | resItems = results[0].GetArray() 21 | self.assertEqual(len(resItems), 3) 22 | self.assertEqual([1, 2, 3], sorted([item.GetBigInteger() for item in resItems])) 23 | 24 | tx, results, total_ops, engine = TestBuild(out, ['neo'], self.GetWallet1(), '', '10') 25 | self.assertEqual(len(results), 1) 26 | resItems = results[0].GetArray() 27 | self.assertEqual(len(resItems), 0) 28 | 29 | tx, results, total_ops, engine = TestBuild(out, ['blah'], self.GetWallet1(), '', '10') 30 | self.assertEqual(len(results), 1) 31 | resItems = results[0].GetArray() 32 | self.assertEqual(len(resItems), 1) 33 | self.assertEqual(resItems[0].GetString(), 'Hello Storage Find') 34 | 35 | tx, results, total_ops, engine = TestBuild(out, ['prefix1e'], self.GetWallet1(), '', '10') 36 | self.assertEqual(len(results), 1) 37 | resItems = results[0].GetArray() 38 | self.assertEqual(len(resItems), 2) 39 | 40 | tx, results, total_ops, engine = TestBuild(out, ['pre'], self.GetWallet1(), '', '10') 41 | self.assertEqual(len(results), 1) 42 | resItems = results[0].GetArray() 43 | self.assertEqual(len(resItems), 2) 44 | 45 | tx, results, total_ops, engine = TestBuild(out, ['pref'], self.GetWallet1(), '', '10') 46 | self.assertEqual(len(results), 1) 47 | resItems = results[0].GetArray() 48 | self.assertEqual(len(resItems), 3) 49 | self.assertEqual(sorted(['prefix1euo', 'prefix1e', 'prefix1__osetuh', ]), sorted([item.GetString() for item in resItems])) 50 | -------------------------------------------------------------------------------- /boa/interop/Neo/Header.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class Header: 4 | 5 | def getmyhash(self): 6 | return GetHash(self) 7 | 8 | @property 9 | def Index(self): 10 | return GetIndex(self) 11 | 12 | @property 13 | def Hash(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetHash(self) 19 | 20 | @property 21 | def Timestamp(self): 22 | """ 23 | 24 | :return: 25 | """ 26 | return GetTimestamp(self) 27 | 28 | @property 29 | def Version(self): 30 | """ 31 | 32 | :return: 33 | """ 34 | return GetVersion(self) 35 | 36 | @property 37 | def PrevHash(self): 38 | """ 39 | 40 | :return: 41 | """ 42 | return GetPrevHash(self) 43 | 44 | @property 45 | def MerkleRoot(self): 46 | """ 47 | 48 | :return: 49 | """ 50 | return GetMerkleRoot(self) 51 | 52 | @property 53 | def ConsensusData(self): 54 | """ 55 | 56 | :return: 57 | """ 58 | return GetConsensusData(self) 59 | 60 | @property 61 | def NextConsensus(self): 62 | """ 63 | 64 | :return: 65 | """ 66 | return GetNextConsensus(self) 67 | 68 | 69 | def GetIndex(header): 70 | """ 71 | 72 | Returns the height/index of a header 73 | 74 | """ 75 | pass 76 | 77 | 78 | def GetHash(header): 79 | """ 80 | 81 | gets the hash of the header 82 | 83 | """ 84 | pass 85 | 86 | 87 | def GetVersion(header): 88 | """ 89 | 90 | gets the version of the header 91 | 92 | """ 93 | pass 94 | 95 | 96 | def GetPrevHash(header): 97 | """ 98 | 99 | gets the hash of the previous header in the blockchain 100 | 101 | """ 102 | pass 103 | 104 | 105 | def GetMerkleRoot(header): 106 | """ 107 | 108 | gets the merkle root of the transactions contained in the block 109 | 110 | """ 111 | pass 112 | 113 | 114 | def GetTimestamp(header): 115 | """ 116 | 117 | gets the timestamp of when the header was created 118 | 119 | """ 120 | pass 121 | 122 | 123 | def GetConsensusData(header): 124 | """ 125 | 126 | gets the address of the consensus 127 | 128 | """ 129 | pass 130 | 131 | 132 | def GetNextConsensus(header): 133 | """ 134 | 135 | gets the address where the next consensus will occur 136 | 137 | """ 138 | pass 139 | -------------------------------------------------------------------------------- /boa/interop/Neo/Asset.py: -------------------------------------------------------------------------------- 1 | 2 | class Asset: 3 | 4 | @property 5 | def AssetId(self): 6 | """ 7 | 8 | :return: 9 | """ 10 | return GetAssetId(self) 11 | 12 | @property 13 | def AssetType(self): 14 | """ 15 | 16 | :return: 17 | """ 18 | return GetAssetType(self) 19 | 20 | @property 21 | def Amount(self): 22 | """ 23 | 24 | :return: 25 | """ 26 | return GetAmount(self) 27 | 28 | @property 29 | def Available(self): 30 | """ 31 | 32 | :return: 33 | """ 34 | return GetAvailable(self) 35 | 36 | @property 37 | def Precision(self): 38 | """ 39 | 40 | :return: 41 | """ 42 | return GetPrecision(self) 43 | 44 | @property 45 | def Owner(self): 46 | """ 47 | 48 | :return: 49 | """ 50 | return GetOwner(self) 51 | 52 | @property 53 | def Admin(self): 54 | """ 55 | 56 | :return: 57 | """ 58 | return GetAdmin(self) 59 | 60 | @property 61 | def Issuer(self): 62 | """ 63 | 64 | :return: 65 | """ 66 | return GetIssuer(self) 67 | 68 | 69 | def GetAssetId(asset): 70 | """ 71 | 72 | :param asset: 73 | """ 74 | pass 75 | 76 | 77 | def GetAssetType(asset): 78 | """ 79 | 80 | :param asset: 81 | """ 82 | pass 83 | 84 | 85 | def GetAmount(asset): 86 | """ 87 | 88 | :param asset: 89 | """ 90 | pass 91 | 92 | 93 | def GetAvailable(asset): 94 | """ 95 | 96 | :param asset: 97 | """ 98 | pass 99 | 100 | 101 | def GetPrecision(asset): 102 | """ 103 | 104 | :param asset: 105 | """ 106 | pass 107 | 108 | 109 | def GetOwner(asset): 110 | """ 111 | 112 | :param asset: 113 | """ 114 | pass 115 | 116 | 117 | def GetAdmin(asset): 118 | """ 119 | 120 | :param asset: 121 | """ 122 | pass 123 | 124 | 125 | def GetIssuer(asset): 126 | """ 127 | 128 | :param asset: 129 | """ 130 | pass 131 | 132 | 133 | def Create(asset_type, name, amount, precision, owner, admin, issuer): 134 | """ 135 | 136 | :param asset_type: 137 | :param name: 138 | :param amount: 139 | :param precision: 140 | :param owner: 141 | :param admin: 142 | :param issuer: 143 | """ 144 | pass 145 | 146 | 147 | def Renew(asset, years): 148 | """ 149 | 150 | :param asset: 151 | :param years: 152 | """ 153 | pass 154 | -------------------------------------------------------------------------------- /boa_test/tests/test_serialization.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.VM.InteropService import StackItem, Array, ByteArray 4 | from neo.Core.IO.BinaryReader import BinaryReader 5 | from neo.IO.MemoryStream import StreamManager 6 | from neo.Prompt.Commands.BuildNRun import TestBuild 7 | 8 | 9 | class TestContract(BoaTest): 10 | 11 | def test_serialization_1(self): 12 | output = Compiler.instance().load('%s/boa_test/example/demo/SerializationTest.py' % TestContract.dirname).default 13 | out = output.write() 14 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '05') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x80\x05\x00\x01a\x02\x01\x03\x80\x03\x00\x01j\x02\x01\x03\x02\x01\x05\x00\x02jk\x00\x07lmnopqr')) 17 | 18 | def test_serialization_2(self): 19 | output = Compiler.instance().load('%s/boa_test/example/demo/SerializationTest.py' % TestContract.dirname).default 20 | out = output.write() 21 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '05') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x80\x05\x00\x01a\x02\x01\x03\x80\x03\x00\x01j\x02\x01\x03\x02\x01\x05\x00\x02jk\x00\x07lmnopqr')) 24 | 25 | stream = StreamManager.GetStream(results[0].GetByteArray()) 26 | reader = BinaryReader(stream) 27 | stack_item = StackItem.DeserializeStackItem(reader) 28 | 29 | self.assertIsInstance(stack_item, Array) 30 | self.assertEqual(stack_item.Count, 5) 31 | self.assertEqual(stack_item.GetArray()[-1].GetString(), 'lmnopqr') 32 | 33 | def test_serialization_3(self): 34 | output = Compiler.instance().load('%s/boa_test/example/demo/SerializationTest.py' % TestContract.dirname).default 35 | out = output.write() 36 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', '05') 37 | self.assertEqual(len(results), 1) 38 | stack_item = results[0].GetArray() 39 | 40 | self.assertIsInstance(stack_item, list) 41 | self.assertEqual(len(stack_item), 5) 42 | self.assertEqual(stack_item[-1].GetString(), 'lmnopqr') 43 | 44 | def test_serialization_4(self): 45 | output = Compiler.instance().load('%s/boa_test/example/demo/SerializationTest.py' % TestContract.dirname).default 46 | out = output.write() 47 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '05') 48 | self.assertEqual(len(results), 1) 49 | stack_item = results[0].GetArray() 50 | 51 | self.assertIsInstance(stack_item, list) 52 | self.assertEqual(len(stack_item), 3) 53 | self.assertEqual(stack_item[-1].GetBigInteger(), 5) 54 | -------------------------------------------------------------------------------- /boa/interop/Neo/Block.py: -------------------------------------------------------------------------------- 1 | from boa.interop.Neo.Header import GetIndex, GetHash, GetPrevHash, GetTimestamp, GetVersion, GetNextConsensus, GetMerkleRoot, GetConsensusData 2 | 3 | 4 | class Block: 5 | 6 | @property 7 | def TransactionCount(self): 8 | """Get the number of transactions in the current block 9 | 10 | :return: 11 | """ 12 | return GetTransactionCount(self) 13 | 14 | @property 15 | def Transactions(self): 16 | """Get all transactions in the current block 17 | 18 | :return: 19 | """ 20 | return GetTransactions(self) 21 | 22 | @property 23 | def Index(self): 24 | """Get the current block height 25 | 26 | Returns: 27 | 28 | """ 29 | return GetIndex(self) 30 | 31 | @property 32 | def Hash(self): 33 | """Get the hash of the block 34 | 35 | :return: 36 | """ 37 | return GetHash(self) 38 | 39 | @property 40 | def Timestamp(self): 41 | """Get the timestamp of the block 42 | 43 | :return: 44 | """ 45 | return GetTimestamp(self) 46 | 47 | @property 48 | def Version(self): 49 | """Get Block version number 50 | 51 | :return: 52 | """ 53 | return GetVersion(self) 54 | 55 | @property 56 | def PrevHash(self): 57 | """Get the hash of the previous block 58 | 59 | :return: 60 | """ 61 | return GetPrevHash(self) 62 | 63 | @property 64 | def MerkleRoot(self): 65 | """Get the Merkle Tree root for all transactions in that block 66 | 67 | :return: 68 | """ 69 | return GetMerkleRoot(self) 70 | 71 | @property 72 | def ConsensusData(self): 73 | """Get consensus data for this block (pseudo-random number generated by consensus node) 74 | 75 | :return: 76 | """ 77 | return GetConsensusData(self) 78 | 79 | @property 80 | def NextConsensus(self): 81 | """Get the hash value for the next bookkeeper contract 82 | 83 | :return: 84 | """ 85 | return GetNextConsensus(self) 86 | 87 | 88 | def GetTransactionCount(block): 89 | """Get the number of transactions in a block 90 | 91 | :return: the number of transactions in a block 92 | """ 93 | pass 94 | 95 | 96 | def GetTransactions(block): 97 | """Get all transactions in a block 98 | 99 | :return: a list of transactions contained in a block 100 | """ 101 | pass 102 | 103 | 104 | def GetTransaction(block, index): 105 | """Get the transaction specified in a block 106 | 107 | :param block: the block to get the transaction from 108 | :param index: the index of the transaction within the block 109 | 110 | """ 111 | 112 | pass 113 | -------------------------------------------------------------------------------- /boa_test/example/blockchain/TransactionTest.py: -------------------------------------------------------------------------------- 1 | # tested 2 | 3 | from boa.interop.Neo.Blockchain import GetTransaction 4 | from boa.interop.Neo.Transaction import * 5 | from boa.interop.Neo.Output import * 6 | from boa.interop.Neo.Input import GetInputHash, GetIndex 7 | from boa.interop.Neo.Witness import * 8 | from boa.builtins import hash160 9 | from boa.interop.System.ExecutionEngine import GetScriptContainer 10 | 11 | NEO = b'\x9b|\xff\xda\xa6t\xbe\xae\x0f\x93\x0e\xbe`\x85\xaf\x90\x93\xe5\xfeV\xb3J\\"\x0c\xcd\xcfn\xfc3o\xc5' 12 | GAS = b'\xe7-(iy\xeel\xb1\xb7\xe6]\xfd\xdf\xb2\xe3\x84\x10\x0b\x8d\x14\x8ewX\xdeB\xe4\x16\x8bqy,`' 13 | 14 | 15 | def Main(operation, txid): 16 | 17 | tx = GetTransaction(txid) 18 | 19 | if not tx: 20 | return False 21 | 22 | if operation == 'get_hash': 23 | return tx.Hash 24 | 25 | elif operation == 'get_type': 26 | return tx.Type 27 | 28 | elif operation == 'get_attrs': 29 | return tx.Attributes 30 | 31 | elif operation == 'get_inputs': 32 | return tx.Inputs 33 | 34 | elif operation == 'get_outputs': 35 | return tx.Outputs 36 | 37 | elif operation == 'get_references': 38 | return tx.References 39 | 40 | elif operation == 'get_unspent': 41 | return tx.UnspentCoins 42 | 43 | elif operation == 'get_output_details': 44 | res = [] 45 | 46 | for item in tx.Outputs: 47 | subres = [] 48 | subres.append(item.Value) 49 | subres.append(item.AssetId) 50 | subres.append(item.ScriptHash) 51 | res.append(subres) 52 | 53 | return res 54 | 55 | elif operation == 'get_reference_details': 56 | res = [] 57 | refs = tx.References 58 | 59 | for item in refs: 60 | subres = [] 61 | subres.append(item.Value) 62 | subres.append(item.AssetId) 63 | subres.append(item.ScriptHash) 64 | res.append(subres) 65 | 66 | return res 67 | 68 | elif operation == 'get_witnesses': 69 | res = [] 70 | witnesses = tx.Witnesses 71 | for item in witnesses: 72 | witness = { 73 | 'verification': item.VerificationScript 74 | } 75 | res.append(witness) 76 | return res 77 | 78 | elif operation == 'get_witness_scripthashes': 79 | tx = GetScriptContainer() 80 | witnesses = tx.Witnesses 81 | res = [] 82 | for item in witnesses: 83 | verification = item.VerificationScript 84 | script_hash = hash160(verification) 85 | res.append(script_hash) 86 | return res 87 | 88 | # name clash with Input.GetHash and Transaction.GetHash 89 | elif operation == 'get_input_details': 90 | res = [] 91 | inputs = tx.Inputs 92 | input1 = inputs[0] 93 | inputhash = GetInputHash(input1) 94 | inputIndex = input1.Index 95 | 96 | return [inputhash, inputIndex] 97 | 98 | return 'unknown operation' 99 | -------------------------------------------------------------------------------- /CHANGELOG.rst: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | All notable changes to this project following the ``v0.4.1`` release are noted in this file 5 | [0.7.2] 2020-06-02 6 | ----------------------- 7 | - production deployment support 8 | 9 | [0.7.1] 2020-06-02 10 | ----------------------- 11 | - fixes script hash in abi file 12 | - adds continuous deployment support 13 | 14 | [0.7.0] 2020-05-19 15 | ----------------------- 16 | - adds integration hooks for neo-debugger-toolkit 17 | - formalizes abi generation 18 | 19 | 20 | [0.6.0] 2019-08-21 21 | ------------------ 22 | - Fix unclosed resource warning 23 | - Various fixes to work with neo-python >= 0.9 24 | 25 | [0.5.6] 2018-10-30 26 | ------------------ 27 | - Fix issues with crowdsale demo test 28 | - Fix issue with ``module.to_s`` method 29 | - Remove ``Neo.Witness.GetInvocationScript`` 30 | 31 | 32 | [0.5.5] 2018-10-17 33 | ------------------ 34 | - Update shift operation test 35 | 36 | 37 | [0.5.4] 2018-10-10 38 | ------------------ 39 | - Add ``Neo.Transaction.GetWitnesses``, ``Neo.Witness.GetInvocationScript``, ``Neo.Witness.GetVerificationScript`` 40 | - Fix ``IsPayable`` 41 | - Fix CI test wallet build issue 42 | 43 | [0.5.3] 2018-09-28 44 | ------------------ 45 | - ``module.to_s()`` method now returns a string instead of printing it 46 | - Update to allow ``CALL_FUNCTION`` opcode within a ``GET_ITER`` instruction. 47 | 48 | [0.5.2] 2018-09-25 49 | ------------------ 50 | - Implement NEP8 call functionality 51 | 52 | [0.5.1] 2018-09-24 53 | ------------------ 54 | - Use reduced sized fixtures for quicker tests 55 | 56 | [0.5.0] 2018-08-26 57 | ------------------ 58 | - Python 3.7 compatibility 59 | 60 | [0.4.9] 2018-08-24 61 | ------------------ 62 | - Updated NEP5 sample 63 | - Updated equality operator conversion 64 | 65 | [0.4.8] 2018-07-05 66 | ------------------ 67 | - Updated module loading to prevent duplicates of modules. 68 | - Updated ``LOAD_ATTR`` parsing to fix bug with multiple ``LOAD_ATTR`` in one statement 69 | - Updated tests for compatibility with ``neo-python`` changes 70 | 71 | [0.4.7] 2018-06-21 72 | ------------------ 73 | - Add support for python opcodes ``DUP_TOP_TWO``, ``ROT_THREE``, and ``ROT_TWO`` 74 | 75 | [0.4.6] 2018-06-19 76 | ------------------ 77 | - Add support for Enumerator/Iterator interop methods in NEO 78 | 79 | [0.4.5] 2018-06-18 80 | ------------------ 81 | - update tests for changes in neo-python 82 | 83 | [0.4.4] 2018-05-31 84 | ------------------ 85 | - remove support for JUMP_IF_TRUE_OR_POP and JUMP_IF_FALSE_OR_POP 86 | - add support for NEP7 triggers 87 | 88 | [0.4.3] 2018-05-14 89 | ------------------ 90 | - add support for JUMP_IF_TRUE_OR_POP and JUMP_IF_FALSE_OR_POP 91 | 92 | [0.4.2] 2018-04-30 93 | ------------------ 94 | - add support for VERIFY opcode to verify arbitrary message 95 | - add support for ``boa.interop.Neo.Storage.Find`` operation 96 | - add tests for comparison ``in`` operator 97 | - update documentation 98 | - Print error msg with file/linenumber/method during tokenization error 99 | 100 | -------------------------------------------------------------------------------- /boa/builtins.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | class list(list): 4 | 5 | """ 6 | list() -> new empty list 7 | list(length=x) -> new list initialized with length of x 8 | """ 9 | 10 | # def __init__(self, length=0): 11 | # pass 12 | pass 13 | 14 | 15 | def concat(str1, str2): 16 | """ 17 | range(str1, str2) -> str object 18 | 19 | Return a string that is the concatenation of the two arguments ( str1 + str2 ) 20 | """ 21 | pass 22 | 23 | 24 | def keys(dictionary): 25 | """ 26 | k = keys(mydict) 27 | 28 | pushes a list of a dictionary keys onto the stack 29 | """ 30 | pass 31 | 32 | 33 | def values(dictionary): 34 | """ 35 | v = values(mydict) 36 | 37 | pushes a list of a dictionary values onto the stack 38 | """ 39 | pass 40 | 41 | 42 | def has_key(dictionary, key): 43 | """ 44 | val = has_key(mydict, 'b') 45 | 46 | pushes a boolean of wether a dictionary has a key onto the stack 47 | """ 48 | pass 49 | 50 | 51 | # This is not necessary. you can use mystring[start:end] 52 | # Actually, it is currently necessary, as mystring[start:end] is not working as expected 53 | 54 | def substr(source, start_index, count): 55 | """ 56 | substr(source, start_index, count) -> list object 57 | 58 | Return a subset of a string `source`, starting at `start_index` and 59 | of length `count` 60 | """ 61 | pass 62 | 63 | 64 | def take(source, count): 65 | """ 66 | take(source, count) -> list object 67 | 68 | Return a subset of a string or list `source`, starting 69 | at index 0 and of length `count` 70 | """ 71 | pass 72 | 73 | 74 | def range(start, stop): 75 | """ 76 | range(start, stop) -> list object 77 | 78 | Return an list that is a a sequence of integers from start (inclusive) 79 | to stop (exclusive). range(i, j) produces i, i+1, i+2, ..., j-1. 80 | """ 81 | 82 | length = stop - start 83 | 84 | out = list(length=length) 85 | 86 | index = 0 87 | 88 | orig_start = start 89 | 90 | while start < stop: 91 | val = index + orig_start 92 | out[index] = val 93 | index = index + 1 94 | start = orig_start + index 95 | 96 | return out 97 | 98 | 99 | def sha1(data): 100 | """ 101 | 102 | :param data: 103 | """ 104 | pass 105 | 106 | 107 | def sha256(data): 108 | """ 109 | 110 | :param data: 111 | """ 112 | pass 113 | 114 | 115 | def hash160(data): 116 | """ 117 | 118 | :param data: 119 | """ 120 | pass 121 | 122 | 123 | def hash256(data): 124 | """ 125 | 126 | :param data: 127 | """ 128 | pass 129 | 130 | 131 | def verify_signature(pubkey, signature, message): 132 | """ 133 | :param pubkey: 134 | :param signature: 135 | :param message: 136 | """ 137 | pass 138 | 139 | 140 | def throw_if_null(item): 141 | pass 142 | 143 | 144 | def breakpoint(): 145 | """ 146 | Adds a breakpoint to the debug map 147 | """ 148 | pass 149 | -------------------------------------------------------------------------------- /boa_test/tests/test_addtest.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_AddTest(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/AddTest.py' % TestContract.dirname).default.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(output, [2], self.GetWallet1(), '02', '02') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBigInteger(), 4) 16 | 17 | tx, results, total_ops, engine = TestBuild(output, [23234], self.GetWallet1(), '02', '02') 18 | self.assertEqual(results[0].GetBigInteger(), 23236) 19 | 20 | tx, results, total_ops, engine = TestBuild(output, [0], self.GetWallet1(), '02', '02') 21 | self.assertEqual(results[0].GetBigInteger(), 2) 22 | 23 | tx, results, total_ops, engine = TestBuild(output, [-112], self.GetWallet1(), '02', '02') 24 | self.assertEqual(results[0].GetBigInteger(), -110) 25 | 26 | def test_AddTest1(self): 27 | 28 | output = Compiler.instance().load('%s/boa_test/example/AddTest1.py' % TestContract.dirname).default.write() 29 | 30 | tx, results, total_ops, engine = TestBuild(output, [1, 2, 3, 4], self.GetWallet1(), '02020202', '02') 31 | self.assertEqual(len(results), 1) 32 | self.assertEqual(results[0].GetBigInteger(), 9) 33 | 34 | tx, results, total_ops, engine = TestBuild(output, [0, 0, 0, 2], self.GetWallet1(), '02020202', '02') 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetBigInteger(), 2) 37 | 38 | tx, results, total_ops, engine = TestBuild(output, [-2, 3, -6, 2], self.GetWallet1(), '02020202', '02') 39 | self.assertEqual(len(results), 1) 40 | self.assertEqual(results[0].GetBigInteger(), -2) 41 | 42 | def test_AddTest2(self): 43 | 44 | output = Compiler.instance().load('%s/boa_test/example/AddTest2.py' % TestContract.dirname).default.write() 45 | 46 | tx, results, total_ops, engine = TestBuild(output, [], self.GetWallet1(), '', '02') 47 | self.assertEqual(len(results), 1) 48 | self.assertEqual(results[0].GetBigInteger(), 3) 49 | 50 | def test_AddTest4(self): 51 | 52 | output = Compiler.instance().load('%s/boa_test/example/AddTest4.py' % TestContract.dirname).default.write() 53 | 54 | tx, results, total_ops, engine = TestBuild(output, [1, 2, 3, 4], self.GetWallet1(), '', '02') 55 | self.assertEqual(len(results), 1) 56 | self.assertEqual(results[0].GetBigInteger(), -9) 57 | 58 | def test_AddVoid(self): 59 | 60 | output = Compiler.instance().load('%s/boa_test/example/AddTestVoid.py' % TestContract.dirname).default 61 | out = output.write() 62 | 63 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', 'ff') 64 | # this should I guess return nothing 65 | # for now it returns an empty byte array 66 | self.assertEqual(len(results), 1) 67 | self.assertEqual(results[0].GetByteArray(), bytearray(b'')) 68 | -------------------------------------------------------------------------------- /boa/interop/BigInteger.py: -------------------------------------------------------------------------------- 1 | 2 | class BigInteger(int): 3 | 4 | @staticmethod 5 | def FromBytes(data, signed=False): 6 | """ 7 | Convert a bytearray into a BigInteger object 8 | 9 | :param data: a bytearray representing an integer 10 | :type data: bytearray 11 | 12 | :param signed: whether or not the bytearray is signed 13 | :type signed: bool 14 | 15 | :return: a BigInteger object 16 | :rtype: ``boa.blockchain.vm.BigInteger`` 17 | 18 | """ 19 | return BigInteger(int.from_bytes(data, 'little', signed=signed)) 20 | 21 | def Equals(self, other): 22 | """ 23 | Compare two BigInteger objects 24 | 25 | :param other: the BigInteger to compare this one with 26 | :type other: BigInteger 27 | 28 | :return: whether the two items are equal 29 | :rtype: bool 30 | 31 | """ 32 | return super(BigInteger, self).__eq__(other) 33 | 34 | def ToByteArray(self, signed=True): 35 | """ 36 | 37 | converts a big integer object into a bytearray 38 | 39 | :param signed: whether or not it should be signed 40 | :type signed: bool 41 | 42 | :return: a bytearray of representing the BigInteger 43 | :rtype: bytearray 44 | 45 | """ 46 | 47 | if self < 0: 48 | try: 49 | return self.to_bytes(1 + ((self.bit_length() + 7) // 8), byteorder='little', signed=True) 50 | except Exception as e: 51 | print("coludnt convert negative number %s " % e) 52 | return False 53 | try: 54 | return self.to_bytes((self.bit_length() + 7) // 8, byteorder='little', signed=signed) 55 | except OverflowError: 56 | return self.to_bytes(1 + ((self.bit_length() + 7) // 8), byteorder='little', signed=signed) 57 | except Exception: 58 | print("COULD NOT CONVERT %s to byte array" % self) 59 | 60 | def __abs__(self, *args, **kwargs): # real signature unknown 61 | return BigInteger(super(BigInteger, self).__abs__(*args, **kwargs)) 62 | 63 | def __add__(self, *args, **kwargs): # real signature unknown 64 | return BigInteger(super(BigInteger, self).__add__(*args, **kwargs)) 65 | 66 | def __mod__(self, *args, **kwargs): # real signature unknown 67 | return BigInteger(super(BigInteger, self).__mod__(*args, **kwargs)) 68 | 69 | def __mul__(self, *args, **kwargs): # real signature unknown 70 | return BigInteger(super(BigInteger, self).__mul__(*args, **kwargs)) 71 | 72 | def __neg__(self, *args, **kwargs): # real signature unknown 73 | return BigInteger(super(BigInteger, self).__neg__(*args, **kwargs)) 74 | 75 | def __str__(self, *args, **kwargs): # real signature unknown 76 | return super(BigInteger, self).__str__(*args, **kwargs) 77 | 78 | def __sub__(self, *args, **kwargs): # real signature unknown 79 | return BigInteger(super(BigInteger, self).__sub__(*args, **kwargs)) 80 | 81 | def __truediv__(self, *args, **kwargs): # real signature unknown 82 | return BigInteger(int(super(BigInteger, self).__truediv__(*args, **kwargs))) 83 | 84 | 85 | ZERO = BigInteger(0) 86 | ONE = BigInteger(1) 87 | -------------------------------------------------------------------------------- /boa_test/tests/test_opcalls.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_opcalls(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/OpCallTest.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, ['omin', 4, 4], self.GetWallet1(), '', '07') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetBigInteger(), 4) 17 | 18 | tx, results, total_ops, engine = TestBuild(out, ['omin', -4, 4], self.GetWallet1(), '', '07') 19 | self.assertEqual(len(results), 1) 20 | self.assertEqual(results[0].GetBigInteger(), -4) 21 | 22 | tx, results, total_ops, engine = TestBuild(out, ['omin', 16, 0], self.GetWallet1(), '', '07') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBigInteger(), 0) 25 | 26 | tx, results, total_ops, engine = TestBuild(out, ['omax', 4, 4], self.GetWallet1(), '', '07') 27 | self.assertEqual(len(results), 1) 28 | self.assertEqual(results[0].GetBigInteger(), 4) 29 | 30 | tx, results, total_ops, engine = TestBuild(out, ['omax', -4, 4], self.GetWallet1(), '', '07') 31 | self.assertEqual(len(results), 1) 32 | self.assertEqual(results[0].GetBigInteger(), 4) 33 | 34 | tx, results, total_ops, engine = TestBuild(out, ['omax', 16, 0], self.GetWallet1(), '', '07') 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetBigInteger(), 16) 37 | 38 | tx, results, total_ops, engine = TestBuild(out, ['oabs', 0, 4], self.GetWallet1(), '', '07') 39 | self.assertEqual(len(results), 1) 40 | self.assertEqual(results[0].GetBigInteger(), 0) 41 | 42 | tx, results, total_ops, engine = TestBuild(out, ['oabs', -4, 4], self.GetWallet1(), '', '07') 43 | self.assertEqual(len(results), 1) 44 | self.assertEqual(results[0].GetBigInteger(), 4) 45 | 46 | tx, results, total_ops, engine = TestBuild(out, ['sha1', 'abc', 4], self.GetWallet1(), '', '07') 47 | self.assertEqual(len(results), 1) 48 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xa9\x99>6G\x06\x81j\xba>%qxP\xc2l\x9c\xd0\xd8\x9d')) 49 | 50 | tx, results, total_ops, engine = TestBuild(out, ['sha256', 'abc', 4], self.GetWallet1(), '', '07') 51 | self.assertEqual(len(results), 1) 52 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xbax\x16\xbf\x8f\x01\xcf\xeaAA@\xde]\xae"#\xb0\x03a\xa3\x96\x17z\x9c\xb4\x10\xffa\xf2\x00\x15\xad')) 53 | 54 | tx, results, total_ops, engine = TestBuild(out, ['hash160', 'abc', 4], self.GetWallet1(), '', '07') 55 | self.assertEqual(len(results), 1) 56 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xbb\x1b\xe9\x8c\x14$D\xd7\xa5j\xa3\x98\x1c9B\xa9x\xe4\xdc3')) 57 | 58 | tx, results, total_ops, engine = TestBuild(out, ['hash256', 'abc', 4], self.GetWallet1(), '', '07') 59 | self.assertEqual(len(results), 1) 60 | self.assertEqual(results[0].GetByteArray(), bytearray(b'O\x8bB\xc2-\xd3r\x9bQ\x9b\xa6\xf6\x8d-\xa7\xcc[-`m\x05\xda\xedZ\xd5\x12\x8c\xc0>lcX')) 61 | -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at tasaunders@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /boa_test/tests/test_methodtest.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Prompt.Commands.BuildNRun import TestBuild 4 | 5 | 6 | class TestContract(BoaTest): 7 | 8 | def test_Method1(self): 9 | output = Compiler.instance().load('%s/boa_test/example/MethodTest.py' % TestContract.dirname).default 10 | out = output.write() 11 | tx, results, total_ops, engine = TestBuild(out, [1, 2], self.GetWallet1(), '0202', '02') 12 | self.assertEqual(len(results), 1) 13 | self.assertEqual(results[0].GetBigInteger(), 7) 14 | 15 | tx, results, total_ops, engine = TestBuild(out, [-3, -100], self.GetWallet1(), '0202', '02') 16 | self.assertEqual(len(results), 1) 17 | self.assertEqual(results[0].GetBigInteger(), -99) 18 | 19 | def test_Method2(self): 20 | output = Compiler.instance().load('%s/boa_test/example/MethodTest2.py' % TestContract.dirname).default 21 | out = output.write() 22 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBigInteger(), 26) 25 | 26 | def test_MethodTest3(self): 27 | output = Compiler.instance().load('%s/boa_test/example/MethodTest3.py' % TestContract.dirname).default 28 | out = output.write() 29 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBigInteger(), 13) 32 | 33 | def test_MethodTest4(self): 34 | output = Compiler.instance().load('%s/boa_test/example/MethodTest4.py' % TestContract.dirname).default 35 | out = output.write() 36 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 37 | self.assertEqual(len(results), 1) 38 | self.assertEqual(results[0].GetBigInteger(), 63) 39 | 40 | def test_MethodTest5(self): 41 | output = Compiler.instance().load('%s/boa_test/example/MethodTest5.py' % TestContract.dirname).default 42 | out = output.write() 43 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 44 | self.assertEqual(len(results), 1) 45 | self.assertEqual(results[0].GetBigInteger(), 15) 46 | 47 | def test_MethodTest6(self): 48 | output = Compiler.instance().load('%s/boa_test/example/Fibonacci.py' % TestContract.dirname).default 49 | out = output.write() 50 | 51 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '02') 52 | self.assertEqual(len(results), 1) 53 | self.assertEqual(results[0].GetBigInteger(), 3) 54 | 55 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '02', '02') 56 | self.assertEqual(len(results), 1) 57 | self.assertEqual(results[0].GetBigInteger(), 5) 58 | 59 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '02', '02') 60 | self.assertEqual(len(results), 1) 61 | self.assertEqual(results[0].GetBigInteger(), 8) 62 | 63 | tx, results, total_ops, engine = TestBuild(out, [7], self.GetWallet1(), '02', '02') 64 | self.assertEqual(len(results), 1) 65 | self.assertEqual(results[0].GetBigInteger(), 13) 66 | 67 | tx, results, total_ops, engine = TestBuild(out, [11], self.GetWallet1(), '02', '02') 68 | self.assertEqual(len(results), 1) 69 | self.assertEqual(results[0].GetBigInteger(), 89) 70 | -------------------------------------------------------------------------------- /boa_test/tests/test_enumerators.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Settings import settings 4 | 5 | settings.USE_DEBUG_STORAGE = True 6 | settings.DEBUG_STORAGE_PATH = './fixtures/debugstorage' 7 | 8 | from neo.Prompt.Commands.BuildNRun import TestBuild 9 | 10 | 11 | class TestContract(BoaTest): 12 | 13 | def test_enumerators(self): 14 | 15 | output = Compiler.instance().load('%s/boa_test/example/demo/EnumeratorTest.py' % TestContract.dirname).default 16 | out = output.write() 17 | 18 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '01') 19 | self.assertEqual(len(results), 1) 20 | self.assertEqual(results[0].GetBoolean(), True) 21 | 22 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '01') 23 | self.assertEqual(len(results), 1) 24 | res = [i.GetBigInteger() for i in results[0].GetArray()] 25 | self.assertEqual(res, [1, 2, 3, 5, 9, 14]) 26 | 27 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', '01') 28 | self.assertEqual(len(results), 1) 29 | res = [i.GetBigInteger() for i in results[0].GetArray()] 30 | self.assertEqual(res, [1, 2, 3, 5, 9, 14]) 31 | 32 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '01') 33 | self.assertEqual(len(results), 1) 34 | res = [i.GetString() for i in results[0].GetArray()] 35 | self.assertEqual(res, ['1', '2', '3', '5', '9', '14', 'a', 'b', 'd', 'f']) 36 | 37 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '02', '01') 38 | self.assertEqual(len(results), 1) 39 | self.assertEqual(results[0].GetBigInteger(), 6) 40 | 41 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '02', '01') 42 | self.assertEqual(len(results), 1) 43 | self.assertEqual(results[0].GetBigInteger(), 6) 44 | 45 | def test_iterators(self): 46 | 47 | output = Compiler.instance().load('%s/boa_test/example/demo/IteratorTest.py' % TestContract.dirname).default 48 | out = output.write() 49 | 50 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '01') 51 | self.assertEqual(len(results), 1) 52 | self.assertEqual(results[0].GetBoolean(), True) 53 | 54 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '01') 55 | self.assertEqual(len(results), 1) 56 | self.assertEqual(results[0].GetBigInteger(), 3) 57 | 58 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', '01') 59 | self.assertEqual(len(results), 1) 60 | res = [i.GetString() for i in results[0].GetArray()] 61 | self.assertEqual(res, ['a', 'c', 'f']) 62 | 63 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '01') 64 | self.assertEqual(len(results), 1) 65 | res = [i.GetBigInteger() for i in results[0].GetArray()] 66 | self.assertEqual(res, [1, 4, 13]) 67 | 68 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '02', '01') 69 | self.assertEqual(len(results), 1) 70 | self.assertEqual(results[0].GetBigInteger(), 3) 71 | 72 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '02', '01') 73 | self.assertEqual(len(results), 1) 74 | res = [i.GetBigInteger() for i in results[0].GetArray()] 75 | self.assertEqual(res, [1, 4, 13]) 76 | -------------------------------------------------------------------------------- /boa_test/tests/test_conditional.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_CompareTest0(self): 10 | 11 | output = Compiler.instance().load('%s/boa_test/example/CompareTest0.py' % TestContract.dirname).default 12 | out = output.write() 13 | 14 | tx, results, total_ops, engine = TestBuild(out, [2, 4], self.GetWallet1(), '0202', '02') 15 | self.assertEqual(len(results), 1) 16 | self.assertEqual(results[0].GetBigInteger(), 2) 17 | 18 | tx, results, total_ops, engine = TestBuild(out, [4, 2], self.GetWallet1(), '0202', '02') 19 | self.assertEqual(len(results), 1) 20 | self.assertEqual(results[0].GetBigInteger(), 3) 21 | 22 | tx, results, total_ops, engine = TestBuild(out, [2, 2], self.GetWallet1(), '0202', '02') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBigInteger(), 2) 25 | 26 | tx, results, total_ops, engine = TestBuild(out, ['b', 'a'], self.GetWallet1(), '0202', '02') 27 | self.assertEqual(len(results), 1) 28 | self.assertEqual(results[0].GetBigInteger(), 3) 29 | 30 | tx, results, total_ops, engine = TestBuild(out, ['a', 'b'], self.GetWallet1(), '0202', '02') 31 | self.assertEqual(len(results), 1) 32 | self.assertEqual(results[0].GetBigInteger(), 2) 33 | 34 | def test_CompareTest1(self): 35 | 36 | output = Compiler.instance().load('%s/boa_test/example/CompareTest1.py' % TestContract.dirname).default 37 | out = output.write() 38 | 39 | tx, results, total_ops, engine = TestBuild(out, [1, 2, 3, 4], self.GetWallet1(), '02020202', '02') 40 | self.assertEqual(len(results), 1) 41 | self.assertEqual(results[0].GetBigInteger(), 11) 42 | 43 | tx, results, total_ops, engine = TestBuild(out, [1, 2, 4, 3], self.GetWallet1(), '02020202', '02') 44 | self.assertEqual(len(results), 1) 45 | self.assertEqual(results[0].GetBigInteger(), 1) 46 | 47 | tx, results, total_ops, engine = TestBuild(out, [1, 4, 3, 5], self.GetWallet1(), '02020202', '02') 48 | self.assertEqual(len(results), 1) 49 | self.assertEqual(results[0].GetBigInteger(), 22) 50 | 51 | tx, results, total_ops, engine = TestBuild(out, [4, 1, 5, 3], self.GetWallet1(), '02020202', '02') 52 | self.assertEqual(len(results), 1) 53 | self.assertEqual(results[0].GetBigInteger(), 3) 54 | 55 | tx, results, total_ops, engine = TestBuild(out, [9, 1, 3, 5], self.GetWallet1(), '02020202', '02') 56 | self.assertEqual(len(results), 1) 57 | self.assertEqual(results[0].GetBigInteger(), 10) 58 | 59 | tx, results, total_ops, engine = TestBuild(out, [9, 5, 3, 5], self.GetWallet1(), '02020202', '02') 60 | self.assertEqual(len(results), 1) 61 | self.assertEqual(results[0].GetBigInteger(), 8) 62 | 63 | def test_CompareTest2(self): 64 | 65 | output = Compiler.instance().load('%s/boa_test/example/CompareTest2.py' % TestContract.dirname).default 66 | out = output.write() 67 | 68 | tx, results, total_ops, engine = TestBuild(out, [2, 2], self.GetWallet1(), '0202', '01') 69 | self.assertEqual(len(results), 1) 70 | self.assertEqual(results[0].GetBoolean(), True) 71 | 72 | tx, results, total_ops, engine = TestBuild(out, [2, 3], self.GetWallet1(), '0202', '01') 73 | self.assertEqual(len(results), 1) 74 | self.assertEqual(results[0].GetBoolean(), False) 75 | -------------------------------------------------------------------------------- /boa_test/tests/test_methodtest_nonnep8.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Prompt.Commands.BuildNRun import TestBuild 4 | 5 | 6 | class TestContract(BoaTest): 7 | 8 | def test_Method1(self): 9 | output = Compiler.instance().load('%s/boa_test/example/MethodTest.py' % TestContract.dirname, use_nep8=False).default 10 | out = output.write() 11 | tx, results, total_ops, engine = TestBuild(out, [1, 2], self.GetWallet1(), '0202', '02') 12 | self.assertEqual(len(results), 1) 13 | self.assertEqual(results[0].GetBigInteger(), 7) 14 | 15 | tx, results, total_ops, engine = TestBuild(out, [-3, -100], self.GetWallet1(), '0202', '02') 16 | self.assertEqual(len(results), 1) 17 | self.assertEqual(results[0].GetBigInteger(), -99) 18 | 19 | def test_Method2(self): 20 | output = Compiler.instance().load('%s/boa_test/example/MethodTest2.py' % TestContract.dirname, use_nep8=False).default 21 | out = output.write() 22 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 23 | self.assertEqual(len(results), 1) 24 | self.assertEqual(results[0].GetBigInteger(), 26) 25 | 26 | def test_MethodTest3(self): 27 | output = Compiler.instance().load('%s/boa_test/example/MethodTest3.py' % TestContract.dirname, use_nep8=False).default 28 | out = output.write() 29 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBigInteger(), 13) 32 | 33 | def test_MethodTest4(self): 34 | output = Compiler.instance().load('%s/boa_test/example/MethodTest4.py' % TestContract.dirname, use_nep8=False).default 35 | out = output.write() 36 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 37 | self.assertEqual(len(results), 1) 38 | self.assertEqual(results[0].GetBigInteger(), 63) 39 | 40 | def test_MethodTest5(self): 41 | output = Compiler.instance().load('%s/boa_test/example/MethodTest5.py' % TestContract.dirname, use_nep8=False).default 42 | out = output.write() 43 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 44 | self.assertEqual(len(results), 1) 45 | self.assertEqual(results[0].GetBigInteger(), 15) 46 | 47 | def test_MethodTest6(self): 48 | output = Compiler.instance().load('%s/boa_test/example/Fibonacci.py' % TestContract.dirname, use_nep8=False).default 49 | out = output.write() 50 | 51 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '02') 52 | self.assertEqual(len(results), 1) 53 | self.assertEqual(results[0].GetBigInteger(), 3) 54 | 55 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '02', '02') 56 | self.assertEqual(len(results), 1) 57 | self.assertEqual(results[0].GetBigInteger(), 5) 58 | 59 | tx, results, total_ops, engine = TestBuild(out, [6], self.GetWallet1(), '02', '02') 60 | self.assertEqual(len(results), 1) 61 | self.assertEqual(results[0].GetBigInteger(), 8) 62 | 63 | tx, results, total_ops, engine = TestBuild(out, [7], self.GetWallet1(), '02', '02') 64 | self.assertEqual(len(results), 1) 65 | self.assertEqual(results[0].GetBigInteger(), 13) 66 | 67 | tx, results, total_ops, engine = TestBuild(out, [11], self.GetWallet1(), '02', '02') 68 | self.assertEqual(len(results), 1) 69 | self.assertEqual(results[0].GetBigInteger(), 89) 70 | -------------------------------------------------------------------------------- /boa_test/tests/test_block.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaFixtureTest 2 | from boa.compiler import Compiler 3 | from neo.Core.TX.Transaction import Transaction 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaFixtureTest): 8 | 9 | def test_Block(self): 10 | output = Compiler.instance().load('%s/boa_test/example/blockchain/BlockTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(out, ['get_hash', 1234], self.GetWallet1(), '02', '02') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xd6\xa7Rf\xed\xba\x82?\xb4\xd0\xa5\xfc\xbf\xed\xf8\xb7\xf2\xea\xf5@\xad\xa8\xd8\xa2\xb8\xf5\xd5\xd8\xfe\x8d\xc4\xe1')) 16 | 17 | tx, results, total_ops, engine = TestBuild(out, ['get_index', 1234], self.GetWallet1(), '02', '02') 18 | self.assertEqual(len(results), 1) 19 | self.assertEqual(results[0].GetBigInteger(), 1234) 20 | 21 | tx, results, total_ops, engine = TestBuild(out, ['get_timestamp', 1234], self.GetWallet1(), '02', '02') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetBigInteger(), 1529948750) 24 | 25 | tx, results, total_ops, engine = TestBuild(out, ['get_index', 1234], self.GetWallet1(), '02', '02') 26 | self.assertEqual(len(results), 1) 27 | self.assertEqual(results[0].GetBigInteger(), 1234) 28 | 29 | tx, results, total_ops, engine = TestBuild(out, ['get_prevhash', 1234], self.GetWallet1(), '02', '02') 30 | self.assertEqual(len(results), 1) 31 | 32 | self.assertEqual(results[0].GetByteArray(), bytearray(b'<\xc4\xe9\x1a\xfe3\xabjo\xff\xfc_\xab=\x14\xa6?%\xbc\x0e$G\xa3\xdaVh\xa1\xddT#\xdcF')) 33 | 34 | tx, results, total_ops, engine = TestBuild(out, ['get_version', 1234], self.GetWallet1(), '02', '02') 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetBigInteger(), 0) 37 | 38 | tx, results, total_ops, engine = TestBuild(out, ['get_nextconsensus', 1234], self.GetWallet1(), '02', '02') 39 | self.assertEqual(len(results), 1) 40 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xbeH\xd3\xa3\xf5\xd1\x00\x13\xab\x9f\xfe\xe4\x89p`xqO\x1e\xa2')) 41 | 42 | tx, results, total_ops, engine = TestBuild(out, ['get_merkleroot', 1234], self.GetWallet1(), '02', '02') 43 | self.assertEqual(len(results), 1) 44 | 45 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xe4FR\xf2U-\xf9\x12\x9c\x15F\x13n\xb5\xc8\xa4z\xac\xb0\xfbK\x1f\xbc\x16*\x14\xd8\xc1\xb8c\xe7\xab')) 46 | 47 | tx, results, total_ops, engine = TestBuild(out, ['get_consensusdata', 1234], self.GetWallet1(), '02', '02') 48 | self.assertEqual(len(results), 1) 49 | self.assertEqual(results[0].GetByteArray(), bytearray(b'$\xbf=\xdb_Qib')) 50 | 51 | tx, results, total_ops, engine = TestBuild(out, ['get_transactioncount', 1234], self.GetWallet1(), '02', '02') 52 | self.assertEqual(len(results), 1) 53 | self.assertEqual(results[0].GetBigInteger(), 1) 54 | 55 | tx, results, total_ops, engine = TestBuild(out, ['get_transactions', 1234], self.GetWallet1(), '02', '02') 56 | self.assertEqual(len(results), 1) 57 | res = results[0].GetArray() 58 | self.assertEqual(len(res), 1) 59 | 60 | tx, results, total_ops, engine = TestBuild(out, ['get_transaction', 1234], self.GetWallet1(), '02', '02') 61 | self.assertEqual(len(results), 1) 62 | res = results[0].GetInterface() 63 | self.assertIsInstance(res, Transaction) 64 | -------------------------------------------------------------------------------- /boa_test/tests/test_concat.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_Concat1(self): 10 | output = Compiler.instance().load('%s/boa_test/example/ConcatTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '07') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetString(), 'helloworld') 16 | 17 | def test_Concat2(self): 18 | output = Compiler.instance().load('%s/boa_test/example/ConcatTest2.py' % TestContract.dirname).default 19 | out = output.write() 20 | 21 | tx, results, total_ops, engine = TestBuild(out, ['concat', "['hello','world']"], self.GetWallet1(), '10', '07') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetString(), 'helloworld') 24 | 25 | tx, results, total_ops, engine = TestBuild(out, ['blah', "['hello','world']"], self.GetWallet1(), '10', '07') 26 | self.assertEqual(len(results), 1) 27 | self.assertEqual(results[0].GetBoolean(), False) 28 | 29 | tx, results, total_ops, engine = TestBuild(out, ['concat', "['blah']"], self.GetWallet1(), '10', '07') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBoolean(), False) 32 | 33 | tx, results, total_ops, engine = TestBuild(out, ['concat', "['hello','world','third']"], self.GetWallet1(), '10', '07') 34 | self.assertEqual(len(results), 1) 35 | self.assertEqual(results[0].GetString(), 'helloworld') 36 | 37 | tx, results, total_ops, engine = TestBuild(out, ['concat', "['1','neo']"], self.GetWallet1(), '10', '07') 38 | self.assertEqual(len(results), 1) 39 | self.assertEqual(results[0].GetString(), '\x01neo') 40 | 41 | tx, results, total_ops, engine = TestBuild(out, ['concat', "['','neo']"], self.GetWallet1(), '10', '07') 42 | self.assertEqual(len(results), 1) 43 | self.assertEqual(results[0].GetString(), 'neo') 44 | 45 | # Testinvoke args need to be fixed 46 | # tx, results, total_ops, engine = TestBuild(out, ['concat',"[bytearray(b'\x01\xa0\x04'),bytearray(b'\x04\x02\x04')]"], self.GetWallet1(), '10','07') 47 | # self.assertEqual(len(results), 1) 48 | # self.assertEqual(results[0].GetByteArray(), bytearray(b'\x01\xa0\x04\x04\x02\x04')) 49 | 50 | def test_Take(self): 51 | output = Compiler.instance().load('%s/boa_test/example/TakeTest.py' % TestContract.dirname).default 52 | out = output.write() 53 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '07') 54 | self.assertEqual(len(results), 1) 55 | self.assertEqual(results[0].GetString(), 'he') 56 | 57 | tx, results, total_ops, engine = TestBuild(out, [0], self.GetWallet1(), '02', '07') 58 | self.assertEqual(len(results), 1) 59 | self.assertEqual(results[0].GetString(), '') 60 | 61 | tx, results, total_ops, engine = TestBuild(out, [12], self.GetWallet1(), '02', '07') 62 | self.assertEqual(len(results), 1) 63 | self.assertEqual(results[0].GetString(), 'helloworld12') 64 | 65 | tx, results, total_ops, engine = TestBuild(out, [40], self.GetWallet1(), '02', '07') 66 | self.assertEqual(len(results), 1) 67 | self.assertEqual(results[0].GetString(), 'helloworld1234567') 68 | 69 | tx, results, total_ops, engine = TestBuild(out, [-2], self.GetWallet1(), '02', '07') 70 | self.assertEqual(len(results), 0) 71 | -------------------------------------------------------------------------------- /boa_test/tests/test_storage.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaFixtureTest 2 | from neo.Settings import settings 3 | from boa.compiler import Compiler 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | import os 6 | import shutil 7 | from logzero import logger 8 | from neo.Blockchain import GetBlockchain 9 | 10 | settings.USE_DEBUG_STORAGE = True 11 | settings.DEBUG_STORAGE_PATH = './fixtures/debugstorage' 12 | 13 | 14 | class TestContract(BoaFixtureTest): 15 | 16 | @classmethod 17 | def tearDownClass(cls): 18 | super(BoaFixtureTest, cls).tearDownClass() 19 | try: 20 | if os.path.exists(settings.debug_storage_leveldb_path): 21 | 22 | shutil.rmtree(settings.debug_storage_leveldb_path) 23 | else: 24 | logger.error("debug storage path doesn't exist") 25 | except Exception as e: 26 | logger.error("couldn't remove debug storage %s " % e) 27 | 28 | def test_Storage(self): 29 | output = Compiler.instance().load('%s/boa_test/example/blockchain/StorageTest.py' % TestContract.dirname).default 30 | out = output.write() 31 | 32 | snapshot = GetBlockchain()._db.createSnapshot() 33 | 34 | tx, results, total_ops, engine = TestBuild(out, ['sget', 'something', 'blah'], self.GetWallet1(), '070505', '05', snapshot=snapshot) 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetByteArray(), b'') 37 | 38 | tx, results, total_ops, engine = TestBuild(out, ['sput', 'something', 'blah'], self.GetWallet1(), '070505', '05', snapshot=snapshot) 39 | self.assertEqual(len(results), 1) 40 | self.assertEqual(results[0].GetByteArray(), b'\x01') 41 | 42 | tx, results, total_ops, engine = TestBuild(out, ['sget', 'something', 'blah'], self.GetWallet1(), '070505', '05', snapshot=snapshot) 43 | self.assertEqual(len(results), 1) 44 | self.assertEqual(results[0].GetByteArray(), b'blah') 45 | 46 | tx, results, total_ops, engine = TestBuild(out, ['sdel', 'something', 'blah'], self.GetWallet1(), '070505', '05', snapshot=snapshot) 47 | self.assertEqual(len(results), 1) 48 | self.assertEqual(results[0].GetByteArray(), b'\x01') 49 | 50 | tx, results, total_ops, engine = TestBuild(out, ['sget', 'something', 'blah'], self.GetWallet1(), '070505', '05', snapshot=snapshot) 51 | self.assertEqual(len(results), 1) 52 | self.assertEqual(results[0].GetByteArray(), b'') 53 | 54 | def test_Storage2(self): 55 | output = Compiler.instance().load('%s/boa_test/example/blockchain/StorageTest.py' % TestContract.dirname).default 56 | out = output.write() 57 | 58 | snapshot = GetBlockchain()._db.createSnapshot() 59 | 60 | tx, results, total_ops, engine = TestBuild(out, ['sget', 100, 10000000000], self.GetWallet1(), '070505', '05', snapshot=snapshot) 61 | self.assertEqual(len(results), 1) 62 | self.assertEqual(results[0].GetByteArray(), b'') 63 | 64 | tx, results, total_ops, engine = TestBuild(out, ['sput', 100, 10000000000], self.GetWallet1(), '070505', '05', snapshot=snapshot) 65 | self.assertEqual(len(results), 1) 66 | self.assertEqual(results[0].GetByteArray(), b'\x01') 67 | 68 | tx, results, total_ops, engine = TestBuild(out, ['sget', 100, 10000000000], self.GetWallet1(), '070505', '05', snapshot=snapshot) 69 | self.assertEqual(len(results), 1) 70 | self.assertEqual(results[0].GetBigInteger(), 10000000000) 71 | 72 | tx, results, total_ops, engine = TestBuild(out, ['sdel', 100, 10000000000], self.GetWallet1(), '070505', '05', snapshot=snapshot) 73 | self.assertEqual(len(results), 1) 74 | self.assertEqual(results[0].GetByteArray(), b'\x01') 75 | 76 | tx, results, total_ops, engine = TestBuild(out, ['sget', 100, 10000000000], self.GetWallet1(), '070505', '05', snapshot=snapshot) 77 | self.assertEqual(len(results), 1) 78 | self.assertEqual(results[0].GetByteArray(), b'') 79 | -------------------------------------------------------------------------------- /boa_test/tests/test_runtime.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaFixtureTest 2 | from boa.compiler import Compiler 3 | from neo.Core.TX.Transaction import Transaction 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | from neo.Prompt.Commands.BuildNRun import TestBuild 7 | from neo.EventHub import events, SmartContractEvent 8 | 9 | 10 | class TestContract(BoaFixtureTest): 11 | 12 | def test_Runtime(self): 13 | 14 | dispatched_events = [] 15 | dispatched_logs = [] 16 | 17 | def on_notif(evt): 18 | dispatched_events.append(evt) 19 | 20 | def on_log(evt): 21 | dispatched_logs.append(evt) 22 | events.on(SmartContractEvent.RUNTIME_NOTIFY, on_notif) 23 | events.on(SmartContractEvent.RUNTIME_LOG, on_log) 24 | 25 | output = Compiler.instance().load('%s/boa_test/example/blockchain/RuntimeTest.py' % TestContract.dirname).default 26 | out = output.write() 27 | 28 | tx, results, total_ops, engine = TestBuild(out, ['get_time', 1], self.GetWallet1(), '0202', '02') 29 | self.assertEqual(len(results), 1) 30 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xc2Y\xa1[')) 31 | 32 | tx, results, total_ops, engine = TestBuild(out, ['check_witness', self.wallet_1_script_hash.Data], self.GetWallet1(), '02', '02') 33 | self.assertEqual(len(results), 1) 34 | self.assertEqual(results[0].GetBoolean(), True) 35 | 36 | tx, results, total_ops, engine = TestBuild(out, ['log', 'hello'], self.GetWallet1(), '02', '02') 37 | self.assertEqual(len(results), 1) 38 | self.assertEqual(results[0].GetBoolean(), True) 39 | self.assertEqual(len(dispatched_logs), 1) 40 | self.assertEqual(dispatched_logs[0].event_payload.Value, 'hello') 41 | 42 | tx, results, total_ops, engine = TestBuild(out, ['notify', 1234], self.GetWallet1(), '02', '02') 43 | self.assertEqual(len(results), 1) 44 | self.assertEqual(results[0].GetBoolean(), True) 45 | self.assertEqual(len(dispatched_events), 1) 46 | self.assertEqual(int.from_bytes(dispatched_events[0].event_payload.Value, 'little'), 1234) 47 | 48 | tx, results, total_ops, engine = TestBuild(out, ['get_trigger', 1234], self.GetWallet1(), '02', '02') 49 | self.assertEqual(len(results), 1) 50 | self.assertEqual(results[0].GetBigInteger(), 16) 51 | 52 | events.off(SmartContractEvent.RUNTIME_NOTIFY, on_notif) 53 | events.off(SmartContractEvent.RUNTIME_LOG, on_log) 54 | 55 | def test_Triggers(self): 56 | 57 | output = Compiler.instance().load('%s/boa_test/example/blockchain/TriggerTypeTest.py' % TestContract.dirname).default 58 | out = output.write() 59 | 60 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '02') 61 | self.assertEqual(len(results), 1) 62 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x10')) 63 | 64 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '02') 65 | self.assertEqual(len(results), 1) 66 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x00')) 67 | 68 | tx, results, total_ops, engine = TestBuild(out, [3], self.GetWallet1(), '02', '02') 69 | self.assertEqual(len(results), 1) 70 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x20')) 71 | 72 | tx, results, total_ops, engine = TestBuild(out, [0], self.GetWallet1(), '02', '02') 73 | self.assertEqual(len(results), 1) 74 | self.assertEqual(results[0].GetBigInteger(), -1) 75 | 76 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '02') 77 | self.assertEqual(len(results), 1) 78 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x11')) 79 | 80 | tx, results, total_ops, engine = TestBuild(out, [5], self.GetWallet1(), '02', '02') 81 | self.assertEqual(len(results), 1) 82 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\x01')) 83 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | =========================================== 3 | Python compiler for the Neo Virtual Machine 4 | =========================================== 5 | 6 | Overview 7 | -------- 8 | 9 | The ``neo-boa`` compiler is a tool for compiling Python files to the 10 | ``.avm`` format for usage in the `Neo Virtual 11 | Machine `__ which is used to 12 | execute contracts on the `Neo 13 | Blockchain `__. 14 | 15 | The compiler supports a subset of the Python language ( in the same way 16 | that a *boa constrictor* is a subset of the Python snake species) 17 | 18 | What does it currently do 19 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | 21 | - Compiles a subset of the Python language to the ``.avm`` format for 22 | use in the `Neo Virtual 23 | Machine `__ 24 | - Works for Python 3.6+ 25 | - Adds debugging map for debugging in neo-python or other NEO debuggers 26 | 27 | 28 | What will it do 29 | ^^^^^^^^^^^^^^^ 30 | 31 | - Compile a larger subset of the Python language 32 | 33 | Get Help or give help 34 | ^^^^^^^^^^^^^^^^^^^^^ 35 | 36 | - Open a new 37 | `issue `__ if you 38 | encounter a problem. 39 | - Or ping **@localhuman** on the `NEO official community 40 | chatroom `__. 41 | - Pull requests welcome. New features, writing tests and documentation 42 | are all needed. 43 | 44 | Installation 45 | ------------ 46 | 47 | Make sure you are using a Python 3.6 or greater virtual environment 48 | 49 | Pip 50 | ^^^ 51 | 52 | :: 53 | 54 | pip install neo-boa 55 | 56 | Docker 57 | ^^^^^^ 58 | 59 | This project contains a Dockerfile to batch compile Python smart 60 | contracts. Clone the repository and navigate into the docker sub 61 | directory of the project. Run the following command to build the 62 | container: 63 | 64 | :: 65 | 66 | docker build -t neo-boa . 67 | 68 | The neo-boa Docker container takes a directory on the host containing 69 | python smart contracts as an input and a directory to compile the .avm 70 | files to as an output. It can be executed like this: 71 | 72 | :: 73 | 74 | docker run -it -v /absolute/path/input_dir:/python-contracts -v /absolute/path/output_dir:/compiled-contracts neo-boa 75 | 76 | The -v (volume) command maps the directories on the host to the 77 | directories within the container. 78 | 79 | Manual 80 | ^^^^^^ 81 | 82 | Clone the repository and navigate into the project directory. Make a 83 | Python 3 virtual environment and activate it via: 84 | 85 | :: 86 | 87 | python3 -m venv venv 88 | source venv/bin/activate 89 | 90 | or, to install Python 3.6 specifically: 91 | 92 | :: 93 | 94 | virtualenv -p /usr/local/bin/python3.6 venv 95 | source venv/bin/activate 96 | 97 | Then, install the requirements: 98 | 99 | :: 100 | 101 | pip install -r requirements.txt 102 | 103 | Usage 104 | ----- 105 | 106 | The compiler may be used like in the following example: 107 | 108 | :: 109 | 110 | from boa.compiler import Compiler 111 | 112 | Compiler.load_and_save('path/to/your/file.py') 113 | 114 | 115 | For legacy purposes, if you wish to compile without NEP8 stack isolation functionality, you may do the following: 116 | 117 | :: 118 | 119 | from boa.compiler import Compiler 120 | 121 | Compiler.load_and_save('path/to/your/file.py', use_nep=False) 122 | 123 | 124 | Docs 125 | ---- 126 | 127 | You can `read the docs 128 | here `__. 129 | 130 | Tests 131 | ----- 132 | 133 | All tests are located in ``boa_test/test``. Tests can be run with the following command ``python -m unittest discover boa_test`` 134 | 135 | License 136 | ------- 137 | 138 | - Open-source `MIT `__. 139 | - Main author is `localhuman `__. 140 | 141 | Donations 142 | --------- 143 | 144 | Accepted at **ATEMNPSjRVvsXmaJW4ZYJBSVuJ6uR2mjQU** 145 | -------------------------------------------------------------------------------- /boa_test/example/demo/ICO_Template.py: -------------------------------------------------------------------------------- 1 | """ 2 | NEP5 Standard 3 | =================================== 4 | 5 | Author: Thomas Saunders 6 | Email: tom@neonexchange.org 7 | 8 | Date: Dec 11 2017 9 | 10 | """ 11 | from boa_test.example.demo.token.txio import get_asset_attachments 12 | from boa_test.example.demo.token.crowdsale import get_circulation, perform_exchange, kyc_register, \ 13 | kyc_status, crowdsale_available_amount, add_to_circulation, TOKEN_INITIAL_AMOUNT, TOKEN_OWNER 14 | from boa_test.example.demo.token.nep5 import NEP5_METHODS, handle_nep51 15 | from boa.interop.Neo.Runtime import GetTrigger, CheckWitness 16 | from boa.interop.Neo.TriggerType import Application, Verification 17 | from boa.interop.Neo.Storage import GetContext, Get, Put 18 | from boa.interop.Neo.Action import RegisterAction 19 | 20 | ctx = GetContext() 21 | 22 | OnTransfer = RegisterAction('transfer', 'addr_from', 'addr_to', 'amount') 23 | 24 | 25 | def Main(operation, args): 26 | """ 27 | 28 | :param operation: str The name of the operation to perform 29 | :param args: list A list of arguments along with the operation 30 | :return: 31 | bytearray: The result of the operation 32 | """ 33 | 34 | trigger = GetTrigger() 35 | 36 | # This is used in the Verification portion of the contract 37 | # To determine whether a transfer of system assets ( NEO/Gas) involving 38 | # This contract's address can proceed 39 | if trigger == Verification(): 40 | 41 | # check if the invoker is the owner of this contract 42 | is_owner = CheckWitness(TOKEN_OWNER) 43 | 44 | # If owner, proceed 45 | if is_owner: 46 | 47 | return True 48 | 49 | # Otherwise, we need to lookup the assets and determine 50 | # If attachments of assets is ok 51 | attachments = get_asset_attachments() 52 | return False 53 | # return can_exchange(ctx,attachments, True) 54 | 55 | elif trigger == Application(): 56 | 57 | for op in NEP5_METHODS: 58 | if operation == op: 59 | return handle_nep51(ctx, operation, args) 60 | 61 | if operation == 'deploy': 62 | return deploy() 63 | 64 | elif operation == 'circulation': 65 | return get_circulation(ctx) 66 | 67 | # the following are handled by crowdsale 68 | 69 | elif operation == 'mintTokens': 70 | return perform_exchange(ctx) 71 | 72 | elif operation == 'crowdsale_register': 73 | return kyc_register(ctx, args) 74 | 75 | elif operation == 'crowdsale_status': 76 | return kyc_status(ctx, args) 77 | 78 | elif operation == 'crowdsale_available': 79 | return crowdsale_available_amount(ctx) 80 | 81 | elif operation == 'get_attachments': 82 | return get_asset_attachments() 83 | 84 | elif operation == 'another_op_1': 85 | return 1 + 1 86 | 87 | elif operation == 'another_op_2': 88 | return 1 + 2 89 | 90 | elif operation == 'another_op_3': 91 | return 1 + 3 92 | 93 | elif operation == 'another_op_4': 94 | return 1 + 4 95 | 96 | elif operation == 'another_op_5': 97 | return 1 + 5 98 | 99 | return 'unknown operation' 100 | 101 | return False 102 | 103 | 104 | def deploy(): 105 | """ 106 | 107 | :param token: Token The token to deploy 108 | :return: 109 | bool: Whether the operation was successful 110 | """ 111 | if not CheckWitness(TOKEN_OWNER): 112 | print("Must be owner to deploy") 113 | return False 114 | 115 | if not Get(ctx, 'initialized'): 116 | # do deploy logic 117 | Put(ctx, 'initialized', 1) 118 | Put(ctx, TOKEN_OWNER, TOKEN_INITIAL_AMOUNT) 119 | # dispatch transfer event for minting 120 | OnTransfer(None, TOKEN_OWNER, TOKEN_INITIAL_AMOUNT) 121 | return add_to_circulation(ctx, TOKEN_INITIAL_AMOUNT) 122 | 123 | return False 124 | -------------------------------------------------------------------------------- /boa_test/tests/test_binops.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | 4 | from neo.Prompt.Commands.BuildNRun import TestBuild 5 | 6 | 7 | class TestContract(BoaTest): 8 | 9 | def test_binops(self): 10 | output = Compiler.instance().load('%s/boa_test/example/BinopTest.py' % TestContract.dirname).default 11 | out = output.write() 12 | 13 | tx, results, total_ops, engine = TestBuild(out, ['&', 4, 4], self.GetWallet1(), '', '07') 14 | self.assertEqual(len(results), 1) 15 | self.assertEqual(results[0].GetBigInteger(), 4) 16 | 17 | tx, results, total_ops, engine = TestBuild(out, ['|', 4, 3], self.GetWallet1(), '', '07') 18 | self.assertEqual(len(results), 1) 19 | self.assertEqual(results[0].GetBigInteger(), 7) 20 | 21 | tx, results, total_ops, engine = TestBuild(out, ['|', 4, 8], self.GetWallet1(), '', '07') 22 | self.assertEqual(len(results), 1) 23 | self.assertEqual(results[0].GetBigInteger(), 12) 24 | 25 | tx, results, total_ops, engine = TestBuild(out, ['^', 4, 4], self.GetWallet1(), '', '07') 26 | self.assertEqual(len(results), 1) 27 | self.assertEqual(results[0].GetBigInteger(), 0) 28 | 29 | tx, results, total_ops, engine = TestBuild(out, ['^', 4, 2], self.GetWallet1(), '', '07') 30 | self.assertEqual(len(results), 1) 31 | self.assertEqual(results[0].GetBigInteger(), 6) 32 | 33 | # tx, results, total_ops, engine = TestBuild(out, ['>>', 16, 2], self.GetWallet1(), '', '07') 34 | # self.assertEqual(len(results), 1) 35 | # self.assertEqual(results[0].GetBigInteger(), 4) 36 | 37 | # tx, results, total_ops, engine = TestBuild(out, ['>>', 16, 0], self.GetWallet1(), '', '07') 38 | # self.assertEqual(len(results), 1) 39 | # self.assertEqual(results[0].GetBigInteger(), 16) 40 | # 41 | # tx, results, total_ops, engine = TestBuild(out, ['>>', 11, 1], self.GetWallet1(), '', '07') 42 | # self.assertEqual(len(results), 1) 43 | # self.assertEqual(results[0].GetBigInteger(), 5) 44 | # 45 | # tx, results, total_ops, engine = TestBuild(out, ['<<', 16, 2], self.GetWallet1(), '', '07') 46 | # self.assertEqual(len(results), 1) 47 | # self.assertEqual(results[0].GetBigInteger(), 64) 48 | # 49 | # tx, results, total_ops, engine = TestBuild(out, ['<<', 16, -2], self.GetWallet1(), '', '07') 50 | # self.assertEqual(len(results), 0) 51 | # 52 | # tx, results, total_ops, engine = TestBuild(out, ['<<', 4, 5], self.GetWallet1(), '', '07') 53 | # self.assertEqual(len(results), 1) 54 | # self.assertEqual(results[0].GetBigInteger(), 128) 55 | 56 | tx, results, total_ops, engine = TestBuild(out, ['%', 16, 2], self.GetWallet1(), '', '07') 57 | self.assertEqual(len(results), 1) 58 | self.assertEqual(results[0].GetBigInteger(), 0) 59 | 60 | tx, results, total_ops, engine = TestBuild(out, ['%', 16, 11], self.GetWallet1(), '', '07') 61 | self.assertEqual(len(results), 1) 62 | self.assertEqual(results[0].GetBigInteger(), 5) 63 | 64 | tx, results, total_ops, engine = TestBuild(out, ['//', 16, 2], self.GetWallet1(), '', '07') 65 | self.assertEqual(len(results), 1) 66 | self.assertEqual(results[0].GetBigInteger(), 8) 67 | 68 | tx, results, total_ops, engine = TestBuild(out, ['//', 16, 7], self.GetWallet1(), '', '07') 69 | self.assertEqual(len(results), 1) 70 | self.assertEqual(results[0].GetBigInteger(), 2) 71 | 72 | tx, results, total_ops, engine = TestBuild(out, ['/', 16, 7], self.GetWallet1(), '', '07') 73 | self.assertEqual(len(results), 1) 74 | self.assertEqual(results[0].GetBigInteger(), 2) 75 | 76 | tx, results, total_ops, engine = TestBuild(out, ['~', 16, 0], self.GetWallet1(), '', '07') 77 | self.assertEqual(len(results), 1) 78 | self.assertEqual(results[0].GetBigInteger(), -17) 79 | 80 | tx, results, total_ops, engine = TestBuild(out, ['~', -3, 0], self.GetWallet1(), '', '07') 81 | self.assertEqual(len(results), 1) 82 | self.assertEqual(results[0].GetBigInteger(), 2) 83 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # Always prefer setuptools over distutils 4 | from setuptools import setup, find_packages 5 | # To use a consistent encoding 6 | from codecs import open 7 | from os import path 8 | 9 | here = path.abspath(path.dirname(__file__)) 10 | 11 | # Get the long description from the README file 12 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 13 | long_description = f.read() 14 | 15 | 16 | setup( 17 | name='neo-boa', 18 | 19 | # Versions should comply with PEP440. For a discussion on single-sourcing 20 | # the version across setup.py and the project code, see 21 | # https://packaging.python.org/en/latest/single_source_version.html 22 | version='0.7.2', 23 | 24 | description='A Python compiler for the Neo Virtual Machine', 25 | long_description=long_description, 26 | 27 | # The project's main homepage. 28 | url='https://github.com/CityOfZion/neo-boa', 29 | 30 | # Author details 31 | author='Thomas Saunders', 32 | author_email='tasaunders@gmail.com', 33 | 34 | # Choose your license 35 | license='MIT', 36 | 37 | # See https://pypi.python.org/pypi?%3Aaction=list_classifiers 38 | classifiers=[ 39 | # How mature is this project? Common values are 40 | # 3 - Alpha 41 | # 4 - Beta 42 | # 5 - Production/Stable 43 | 'Development Status :: 3 - Alpha', 44 | 45 | # Indicate who your project is intended for 46 | 'Intended Audience :: Developers', 47 | 'Topic :: Software Development :: Build Tools', 48 | 49 | # Pick your license as you wish (should match "license" above) 50 | 'License :: OSI Approved :: MIT License', 51 | 52 | # Specify the Python versions you support here. In particular, ensure 53 | # that you indicate whether you support Python 2, Python 3 or both. 54 | 'Programming Language :: Python :: 3.6', 55 | 'Programming Language :: Python :: 3.7', 56 | ], 57 | 58 | # What does your project relate to? 59 | keywords='compiler NEO .avm blockchain smartcontract development dApp', 60 | 61 | # You can just specify the packages manually here if your project is 62 | # simple. Or you can use find_packages(). 63 | packages=find_packages(), 64 | 65 | # Alternatively, if you want to distribute just a my_module.py, uncomment 66 | # this: 67 | # py_modules=["my_module"], 68 | 69 | # List run-time dependencies here. These will be installed by pip when 70 | # your project is installed. For an analysis of "install_requires" vs pip's 71 | # requirements files see: 72 | # https://packaging.python.org/en/latest/requirements.html 73 | 74 | 75 | install_requires=[ 76 | 'bytecode==0.10.0', 77 | 'astor', 78 | 'logzero==1.5.0' 79 | ], 80 | 81 | python_requires='>=3.6', 82 | 83 | # List additional groups of dependencies here (e.g. development 84 | # dependencies). You can install these using the following syntax, 85 | # for example: 86 | # $ pip install -e .[dev,test] 87 | extras_require={ 88 | 'dev': ['twine','wheel','sphinx','autopep8','pep8','sphinx-rtd-theme'], 89 | 'test': ['coverage'], 90 | }, 91 | 92 | # If there are data files included in your packages that need to be 93 | # installed, specify them here. If using Python 2.6 or less, then these 94 | # have to be included in MANIFEST.in as well. 95 | #package_data={ 96 | # 'sample': ['package_data.dat'], 97 | #}, 98 | 99 | # Although 'package_data' is the preferred approach, in some case you may 100 | # need to place data files outside of your packages. See: 101 | # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa 102 | # In this case, 'data_file' will be installed into '/my_data' 103 | #data_files=[('my_data', ['data/data_file'])], 104 | 105 | # To provide executable scripts, use entry points in preference to the 106 | # "scripts" keyword. Entry points provide cross-platform support and allow 107 | # pip to create the appropriate form of executable for the target platform. 108 | entry_points={ 109 | 'console_scripts': [ 110 | 'neo-boa=boa.cli:main', 111 | ], 112 | }, 113 | ) 114 | -------------------------------------------------------------------------------- /boa_test/tests/test_lists.py: -------------------------------------------------------------------------------- 1 | from boa_test.tests.boa_test import BoaTest 2 | from boa.compiler import Compiler 3 | from neo.Prompt.Commands.BuildNRun import TestBuild 4 | 5 | 6 | class TestContract(BoaTest): 7 | 8 | def test_list0(self): 9 | output = Compiler.instance().load('%s/boa_test/example/ArrayTest.py' % TestContract.dirname).default 10 | out = output.write() 11 | tx, results, total_ops, engine = TestBuild(out, [0], self.GetWallet1(), '02', '02') 12 | self.assertEqual(len(results), 1) 13 | self.assertEqual(results[0].GetBigInteger(), 1) 14 | 15 | tx, results, total_ops, engine = TestBuild(out, [1], self.GetWallet1(), '02', '02') 16 | self.assertEqual(len(results), 1) 17 | self.assertEqual(results[0].GetBigInteger(), 6) 18 | 19 | tx, results, total_ops, engine = TestBuild(out, [2], self.GetWallet1(), '02', '02') 20 | self.assertEqual(len(results), 1) 21 | self.assertEqual(results[0].GetBigInteger(), 3) 22 | 23 | tx, results, total_ops, engine = TestBuild(out, [4], self.GetWallet1(), '02', '02') 24 | self.assertEqual(len(results), 1) 25 | self.assertEqual(results[0].GetBigInteger(), 8) 26 | 27 | tx, results, total_ops, engine = TestBuild(out, [8], self.GetWallet1(), '02', '02') 28 | self.assertEqual(len(results), 1) 29 | self.assertEqual(results[0].GetBigInteger(), 9) 30 | 31 | def test_list1(self): 32 | output = Compiler.instance().load('%s/boa_test/example/ArrayTest1.py' % TestContract.dirname).default 33 | out = output.write() 34 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 35 | self.assertEqual(len(results), 1) 36 | self.assertEqual(results[0].GetBoolean(), True) 37 | 38 | def test_list2(self): 39 | output = Compiler.instance().load('%s/boa_test/example/ArrayTest2.py' % TestContract.dirname).default 40 | out = output.write() 41 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 42 | self.assertEqual(len(results), 1) 43 | self.assertEqual(results[0].GetByteArray(), bytearray(b'\xa0')) 44 | 45 | def test_list3(self): 46 | output = Compiler.instance().load('%s/boa_test/example/ArrayTest3.py' % TestContract.dirname).default 47 | out = output.write() 48 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 49 | self.assertEqual(len(results), 1) 50 | res = results[0].GetArray() 51 | self.assertEqual(len(res), 3) 52 | self.assertEqual(res[0].GetBigInteger(), 1) 53 | 54 | def test_list4(self): 55 | output = Compiler.instance().load('%s/boa_test/example/AppendTest.py' % TestContract.dirname).default 56 | out = output.write() 57 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 58 | self.assertEqual(len(results), 1) 59 | res = results[0].GetArray() 60 | self.assertEqual(len(res), 2) 61 | self.assertEqual(res[0].GetBigInteger(), 6) 62 | 63 | def test_list5(self): 64 | output = Compiler.instance().load('%s/boa_test/example/ArrayRemoveTest.py' % TestContract.dirname).default 65 | out = output.write() 66 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 67 | self.assertEqual(len(results), 1) 68 | res = results[0].GetArray() 69 | self.assertEqual(len(res), 3) 70 | self.assertEqual(res[0].GetBigInteger(), 16) 71 | self.assertEqual(res[1].GetBigInteger(), 3) 72 | 73 | def test_list6(self): 74 | output = Compiler.instance().load('%s/boa_test/example/ArrayReverseTest.py' % TestContract.dirname).default 75 | out = output.write() 76 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 77 | self.assertEqual(len(results), 1) 78 | self.assertEqual(results[0].GetString(), 'blah') 79 | 80 | def test_list7(self): 81 | output = Compiler.instance().load('%s/boa_test/example/ArrayTest4.py' % TestContract.dirname).default 82 | out = output.write() 83 | tx, results, total_ops, engine = TestBuild(out, [], self.GetWallet1(), '', '02') 84 | self.assertEqual(len(results), 1) 85 | res = results[0].GetArray() 86 | self.assertEqual(len(res), 3) 87 | self.assertEqual(res[0].GetBigInteger(), 3) 88 | --------------------------------------------------------------------------------