*: support invoking methods by offset

Allow to invoke methods by offset:
1. Every invoked contract must have manifest.
2. Check arguments count on invocation.
3. Change AppCall to a regular syscall.
4. Add test suite for `System.Contract.Call`.
This commit is contained in:
Evgenii Stratonikov 2020-07-23 18:13:02 +03:00
parent e87eba51f9
commit d2ddf7b7cb
14 changed files with 272 additions and 117 deletions

View file

@ -11,83 +11,91 @@ const (
)
func Main(operation string, args []interface{}) interface{} {
runtime.Notify("contract call", operation, args)
switch operation {
case "Put":
ctx := storage.GetContext()
storage.Put(ctx, args[0].([]byte), args[1].([]byte))
return true
case "totalSupply":
return totalSupply
case "decimals":
return decimals
case "name":
return "Rubl"
case "symbol":
return "RUB"
case "balanceOf":
ctx := storage.GetContext()
addr := args[0].([]byte)
if len(addr) != 20 {
runtime.Log("invalid address")
return false
}
var amount int
val := storage.Get(ctx, addr)
if val != nil {
amount = val.(int)
}
runtime.Notify("balanceOf", addr, amount)
return amount
case "transfer":
ctx := storage.GetContext()
from := args[0].([]byte)
if len(from) != 20 {
runtime.Log("invalid 'from' address")
return false
}
to := args[1].([]byte)
if len(to) != 20 {
runtime.Log("invalid 'to' address")
return false
}
amount := args[2].(int)
if amount < 0 {
runtime.Log("invalid amount")
return false
}
var fromBalance int
val := storage.Get(ctx, from)
if val != nil {
fromBalance = val.(int)
}
if fromBalance < amount {
runtime.Log("insufficient funds")
return false
}
fromBalance -= amount
storage.Put(ctx, from, fromBalance)
var toBalance int
val = storage.Get(ctx, to)
if val != nil {
toBalance = val.(int)
}
toBalance += amount
storage.Put(ctx, to, toBalance)
runtime.Notify("transfer", from, to, amount)
return true
case "init":
ctx := storage.GetContext()
h := runtime.GetExecutingScriptHash()
amount := totalSupply
storage.Put(ctx, h, amount)
runtime.Notify("transfer", []byte{}, h, amount)
return true
default:
panic("invalid operation")
}
panic("invoking via Main is no longer supported") // catch possible bugs
}
func Init() bool {
ctx := storage.GetContext()
h := runtime.GetExecutingScriptHash()
amount := totalSupply
storage.Put(ctx, h, amount)
runtime.Notify("transfer", []byte{}, h, amount)
return true
}
func Transfer(from, to []byte, amount int) bool {
ctx := storage.GetContext()
if len(from) != 20 {
runtime.Log("invalid 'from' address")
return false
}
if len(to) != 20 {
runtime.Log("invalid 'to' address")
return false
}
if amount < 0 {
runtime.Log("invalid amount")
return false
}
var fromBalance int
val := storage.Get(ctx, from)
if val != nil {
fromBalance = val.(int)
}
if fromBalance < amount {
runtime.Log("insufficient funds")
return false
}
fromBalance -= amount
storage.Put(ctx, from, fromBalance)
var toBalance int
val = storage.Get(ctx, to)
if val != nil {
toBalance = val.(int)
}
toBalance += amount
storage.Put(ctx, to, toBalance)
runtime.Notify("transfer", from, to, amount)
return true
}
func BalanceOf(addr []byte) int {
ctx := storage.GetContext()
if len(addr) != 20 {
runtime.Log("invalid address")
return 0
}
var amount int
val := storage.Get(ctx, addr)
if val != nil {
amount = val.(int)
}
runtime.Notify("balanceOf", addr, amount)
return amount
}
func Name() string {
return "Rubl"
}
func Symbol() string {
return "RUB"
}
func Decimals() int {
return decimals
}
func TotalSupply() int {
return totalSupply
}
func PutValue(key []byte, value []byte) bool {
ctx := storage.GetContext()
storage.Put(ctx, key, value)
return true
}