Skip to content
This repository has been archived by the owner on Nov 15, 2021. It is now read-only.

Commit

Permalink
Feature sc apis (#113)
Browse files Browse the repository at this point in the history
* initial dynamic invoke work

* initial implementation of dynamic invoke

* added check for contract hasdynamicinvoke before doing dynamic invoe

* adding additional SC api

* removed DYNAMICCALL from dynamic contract invoke implementation

* style fixes

* adding additional sc API

* update json structure of ContractState

* fix style

* removed Neo.Runtime.GetCurrentBlock

* adding get unspents functionality

* merge stuff

* fix db version
  • Loading branch information
localhuman committed Dec 10, 2017
1 parent b71806f commit 5ce125d
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 50 deletions.
5 changes: 5 additions & 0 deletions neo/Core/Blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ def Height(self):
# abstract
pass

@property
def CurrentBlock(self):
# abstract
pass

def AddBlock(self, block):
# abstract
pass
Expand Down
17 changes: 13 additions & 4 deletions neo/Core/FunctionCode.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
from neo.IO.Mixins import SerializableMixin
import binascii
from neo.Cryptography.Helper import hash_to_wallet_address
from neo.Cryptography.Helper import hash_to_wallet_address
from neo.Cryptography.Crypto import Crypto


Expand All @@ -16,9 +15,19 @@ class FunctionCode(SerializableMixin):

_scriptHash = None

NeedsStorage = False
ContractProperties = None

@property
def HasStorage(self):
from neo.Core.State.ContractState import ContractPropertyState
return self.ContractProperties & ContractPropertyState.HasStorage > 0

@property
def HasDynamicInvoke(self):
from neo.Core.State.ContractState import ContractPropertyState
return self.ContractProperties & ContractPropertyState.HasDynamicInvoke > 0

def __init__(self, script=None, param_list=None, return_type=None, needs_storage=False):
def __init__(self, script=None, param_list=None, return_type=None, contract_properties=0):
self.Script = script
if param_list is None:
self.ParameterList = []
Expand All @@ -27,7 +36,7 @@ def __init__(self, script=None, param_list=None, return_type=None, needs_storage

self.ReturnType = return_type

self.NeedsStorage = needs_storage
self.ContractProperties = contract_properties

def ScriptHash(self):
if self._scriptHash is None:
Expand Down
39 changes: 29 additions & 10 deletions neo/Core/State/ContractState.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@

from .StateBase import StateBase
import sys
from neo.IO.BinaryReader import BinaryReader
from neo.IO.MemoryStream import MemoryStream, StreamManager
from neo.IO.MemoryStream import StreamManager
from neo.Core.FunctionCode import FunctionCode

from enum import IntEnum


class ContractPropertyState(IntEnum):
NoProperty = 0
HasStorage = 1 << 0
HasDynamicInvoke = 1 << 1


class ContractState(StateBase):

Code = None
HasStorage = False
ContractProperties = None
Name = None
CodeVersion = None
Author = None
Email = None
Description = None

def __init__(self, code=None, has_storage=False, name=None, version=None, author=None, email=None, description=None):
@property
def HasStorage(self):
return self.ContractProperties & ContractPropertyState.HasStorage > 0

@property
def HasDynamicInvoke(self):
return self.ContractProperties & ContractPropertyState.HasDynamicInvoke > 0

def __init__(self, code=None, contract_properties=0, name=None, version=None, author=None, email=None, description=None):
self.Code = code
self.HasStorage = has_storage
self.ContractProperties = contract_properties
self.Name = name
self.CodeVersion = version
self.Author = author
Expand All @@ -35,7 +49,7 @@ def Deserialize(self, reader):
code.Deserialize(reader)
self.Code = code

self.HasStorage = reader.ReadBool()
self.ContractProperties = reader.ReadUInt8()
self.Name = reader.ReadVarString(max=252)
self.CodeVersion = reader.ReadVarString(max=252)
self.Author = reader.ReadVarString(max=252)
Expand All @@ -57,7 +71,7 @@ def Serialize(self, writer):
super(ContractState, self).Serialize(writer)

self.Code.Serialize(writer)
writer.WriteBool(self.HasStorage)
writer.WriteUInt8(self.ContractProperties)
writer.WriteVarString(self.Name)
writer.WriteVarString(self.CodeVersion)
writer.WriteVarString(self.Author)
Expand All @@ -75,14 +89,19 @@ def ToJson(self):
except Exception as e:
pass

print("self contract properties: %s " % self.ContractProperties)

return {

'version': self.StateVersion,
'code': codejson,
'storage': self.HasStorage,
'name': name,
'code_version': self.CodeVersion.decode('utf-8'),
'author': self.Author.decode('utf-8'),
'email': self.Email.decode('utf-8'),
'description': self.Description.decode('utf-8')
'description': self.Description.decode('utf-8'),
'properties': {
'storage': self.HasStorage,
'dynamic_invoke': self.HasDynamicInvoke
}
}
6 changes: 6 additions & 0 deletions neo/Implementations/Blockchains/LevelDB/CachedScriptTable.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,9 @@ def GetScript(self, script_hash):
return contract.Code.Script

return None

def GetContractState(self, script_hash):

contract = self.contracts.TryGet(script_hash)

return contract
30 changes: 30 additions & 0 deletions neo/Implementations/Blockchains/LevelDB/LevelDBBlockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,12 @@ class LevelDBBlockchain(Blockchain):

_verify_blocks = False

# this is the version of the database
# should not be updated for network version changes
_sysversion = b'/NEO:2.0.1/'

_persisting_block = None

@property
def CurrentBlockHash(self):
try:
Expand Down Expand Up @@ -83,6 +87,12 @@ def HeaderHeight(self):
def Height(self):
return self._current_block_height

@property
def CurrentBlock(self):
if self._persisting_block:
return self._persisting_block
return self.GetBlockByHeight(self.Height)

@property
def Path(self):
return self._path
Expand Down Expand Up @@ -251,6 +261,23 @@ def GetAllSpentCoins(self):

return coins.Keys

def GetUnspent(self, hash, index):

sn = self._db.snapshot()
coins = DBCollection(self._db, sn, DBPrefix.ST_SpentCoin, UnspentCoinState)

state = coins.TryGet(hash)

if state is None:
return None
if index >= len(state.Items):
return None
if state.Items[index] & CoinState.Spent > 0:
return None
tx, height = self.GetTransaction(hash)

return tx.outputs[index]

def GetSpentCoins(self, tx_hash):

if type(tx_hash) is not bytes:
Expand Down Expand Up @@ -569,6 +596,8 @@ def BlockCacheCount(self):

def Persist(self, block):

self._persisting_block = block

sn = self._db.snapshot()
accounts = DBCollection(self._db, sn, DBPrefix.ST_Account, AccountState)
unspentcoins = DBCollection(self._db, sn, DBPrefix.ST_Coin, UnspentCoinState)
Expand Down Expand Up @@ -723,6 +752,7 @@ def Persist(self, block):

wb.put(DBPrefix.SYS_CurrentBlock, block.Hash.ToBytes() + block.IndexBytes())
self._current_block_height = block.Index
self._persisting_block = None

def PersistBlocks(self):
# logger.info("PERRRRRSISST:: Hheight, b height, cache: %s/%s %s --%s %s" % (self.Height, self.HeaderHeight, len(self._block_cache), self.CurrentHeaderHash, self.BlockSearchTries))
Expand Down
2 changes: 1 addition & 1 deletion neo/Network/Payloads/test_payloads.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class PayloadTestCase(NeoTestCase):

port = 20333
nonce = random.randint(12949672, 42949672)
ua = "/NEO:2.0.1/"
ua = "/NEO:2.4.1/"

payload = None

Expand Down
2 changes: 1 addition & 1 deletion neo/Prompt/Commands/BuildNRun.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ def DoRun(contract_script, arguments, wallet, path):
if wallet is not None:

f_args = arguments[2:]
i_args = arguments[5:]
i_args = arguments[6:]

script = GatherLoadedContractParams(f_args, contract_script)

Expand Down
50 changes: 37 additions & 13 deletions neo/Prompt/Commands/LoadSmartContract.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import binascii
from neo.Prompt.Utils import parse_param
from neo.Core.FunctionCode import FunctionCode
from neo.Core.State.ContractState import ContractPropertyState
from prompt_toolkit import prompt
import json
from neo.VM.ScriptBuilder import ScriptBuilder
Expand Down Expand Up @@ -55,8 +56,8 @@ def ImportContractAddr(wallet, args):

def LoadContract(args):

if len(args) < 4:
print("please specify contract to load like such: 'import contract {path} {params} {return_type} {needs_storage}'")
if len(args) < 5:
print("please specify contract to load like such: 'import contract {path} {params} {return_type} {needs_storage} {needs_dynamic_invoke}'")
return

path = args[0]
Expand All @@ -71,6 +72,17 @@ def LoadContract(args):
return_type = return_type.encode('utf-8')

needs_storage = bool(parse_param(args[3]))
needs_dynamic_invoke = bool(parse_param(args[4]))

contract_properties = 0

if needs_storage:
contract_properties += ContractPropertyState.HasStorage

if needs_dynamic_invoke:
contract_properties += ContractPropertyState.HasDynamicInvoke

print("contract properties: %s " % contract_properties)

script = None

Expand All @@ -97,7 +109,7 @@ def LoadContract(args):
plist = bytearray(binascii.unhexlify(params))
except Exception as e:
plist = bytearray(b'\x10')
function_code = FunctionCode(script=script, param_list=bytearray(plist), return_type=binascii.unhexlify(return_type), needs_storage=needs_storage)
function_code = FunctionCode(script=script, param_list=bytearray(plist), return_type=binascii.unhexlify(return_type), contract_properties=contract_properties)

return function_code

Expand All @@ -107,6 +119,8 @@ def LoadContract(args):

def GatherLoadedContractParams(args, script):

if len(args) < 4:
raise Exception("please specify contract properties like {params} {return_type} {needs_storage} {needs_dynamic_invoke}")
params = parse_param(args[0], ignore_int=True, prefer_hex=False)

if type(params) is str:
Expand All @@ -118,8 +132,17 @@ def GatherLoadedContractParams(args, script):
return_type = return_type.encode('utf-8')

needs_storage = bool(parse_param(args[2]))
needs_dynamic_invoke = bool(parse_param(args[3]))

contract_properties = 0

if needs_storage:
contract_properties += ContractPropertyState.HasStorage

if needs_dynamic_invoke:
contract_properties += ContractPropertyState.HasDynamicInvoke

out = generate_deploy_script(script, needs_storage=needs_storage, return_type=return_type, parameter_list=params)
out = generate_deploy_script(script, contract_properties=contract_properties, return_type=return_type, parameter_list=params)

return out

Expand Down Expand Up @@ -164,21 +187,22 @@ def GatherContractDetails(function_code, prompter):
style=prompter.token_style)

print("Creating smart contract....")
print(" Name: %s " % name)
print(" Version: %s" % version)
print(" Author: %s " % author)
print(" Email: %s " % email)
print(" Description: %s " % description)
print("Needs Storage: %s " % function_code.NeedsStorage)
print(" Name: %s " % name)
print(" Version: %s" % version)
print(" Author: %s " % author)
print(" Email: %s " % email)
print(" Description: %s " % description)
print(" Needs Storage: %s " % function_code.HasStorage)
print(" Needs Dynamic Invoke: %s " % function_code.HasDynamicInvoke)
print(json.dumps(function_code.ToJson(), indent=4))

return generate_deploy_script(function_code.Script, name, version, author, email, description,
function_code.NeedsStorage, ord(function_code.ReturnType),
function_code.ContractProperties, ord(function_code.ReturnType),
function_code.ParameterList)


def generate_deploy_script(script, name='test', version='test', author='test', email='test',
description='test', needs_storage=False, return_type=b'\xff', parameter_list=[]):
description='test', contract_properties=0, return_type=b'\xff', parameter_list=[]):
sb = ScriptBuilder()

plist = parameter_list
Expand All @@ -192,7 +216,7 @@ def generate_deploy_script(script, name='test', version='test', author='test', e
sb.push(binascii.hexlify(author.encode('utf-8')))
sb.push(binascii.hexlify(version.encode('utf-8')))
sb.push(binascii.hexlify(name.encode('utf-8')))
sb.WriteBool(needs_storage)
sb.push(contract_properties)
sb.push(return_type)
sb.push(plist)
sb.WriteVarData(script)
Expand Down
Loading

0 comments on commit 5ce125d

Please sign in to comment.