core: fix contract state's Properties to use PropertyState

PublishTX only had one of these flags, but newer contracts (created via the
interop function) can have more and these flags are aggregated into one field
that uses PropertyState enumeration (it's used to publish contract, so
supposedly it's also a nice choice for contract state storage).
This commit is contained in:
Roman Khimov 2019-10-10 17:56:58 +03:00
parent acb7ef7fbd
commit 238c590ddb
4 changed files with 67 additions and 29 deletions

View file

@ -13,6 +13,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm"
"github.com/pkg/errors"
@ -390,11 +391,15 @@ func (bc *Blockchain) storeBlock(block *Block) error {
case *transaction.EnrollmentTX:
case *transaction.StateTX:
case *transaction.PublishTX:
var properties smartcontract.PropertyState
if t.NeedStorage {
properties |= smartcontract.HasStorage
}
contract := &ContractState{
Script: t.Script,
ParamList: t.ParamList,
ReturnType: t.ReturnType,
HasStorage: t.NeedStorage,
Properties: properties,
Name: t.Name,
CodeVersion: t.CodeVersion,
Author: t.Author,

View file

@ -13,17 +13,15 @@ type Contracts map[util.Uint160]*ContractState
// ContractState holds information about a smart contract in the NEO blockchain.
type ContractState struct {
Script []byte
ParamList []smartcontract.ParamType
ReturnType smartcontract.ParamType
Properties []byte
Name string
CodeVersion string
Author string
Email string
Description string
HasStorage bool
HasDynamicInvoke bool
Script []byte
ParamList []smartcontract.ParamType
ReturnType smartcontract.ParamType
Properties smartcontract.PropertyState
Name string
CodeVersion string
Author string
Email string
Description string
scriptHash util.Uint160
}
@ -52,14 +50,12 @@ func (a *ContractState) DecodeBinary(br *io.BinReader) {
a.ParamList[k] = smartcontract.ParamType(paramBytes[k])
}
br.ReadLE(&a.ReturnType)
a.Properties = br.ReadBytes()
br.ReadLE(&a.Properties)
a.Name = br.ReadString()
a.CodeVersion = br.ReadString()
a.Author = br.ReadString()
a.Email = br.ReadString()
a.Description = br.ReadString()
br.ReadLE(&a.HasStorage)
br.ReadLE(&a.HasDynamicInvoke)
a.createHash()
}
@ -71,14 +67,12 @@ func (a *ContractState) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(a.ParamList[k])
}
bw.WriteLE(a.ReturnType)
bw.WriteBytes(a.Properties)
bw.WriteLE(a.Properties)
bw.WriteString(a.Name)
bw.WriteString(a.CodeVersion)
bw.WriteString(a.Author)
bw.WriteString(a.Email)
bw.WriteString(a.Description)
bw.WriteLE(a.HasStorage)
bw.WriteLE(a.HasDynamicInvoke)
}
// ScriptHash returns a contract script hash.
@ -93,3 +87,18 @@ func (a *ContractState) ScriptHash() util.Uint160 {
func (a *ContractState) createHash() {
a.scriptHash = hash.Hash160(a.Script)
}
// HasStorage checks whether the contract has storage property set.
func (cs *ContractState) HasStorage() bool {
return (cs.Properties & smartcontract.HasStorage) != 0
}
// HasDynamicInvoke checks whether the contract has dynamic invoke property set.
func (cs *ContractState) HasDynamicInvoke() bool {
return (cs.Properties & smartcontract.HasDynamicInvoke) != 0
}
// IsPayable checks whether the contract has payable property set.
func (cs *ContractState) IsPayable() bool {
return (cs.Properties & smartcontract.IsPayable) != 0
}

View file

@ -13,17 +13,15 @@ func TestEncodeDecodeContractState(t *testing.T) {
script := []byte("testscript")
contract := &ContractState{
Script: script,
ParamList: []smartcontract.ParamType{smartcontract.StringType, smartcontract.IntegerType, smartcontract.Hash160Type},
ReturnType: smartcontract.BoolType,
Properties: []byte("smth"),
Name: "Contracto",
CodeVersion: "1.0.0",
Author: "Joe Random",
Email: "joe@example.com",
Description: "Test contract",
HasStorage: true,
HasDynamicInvoke: false,
Script: script,
ParamList: []smartcontract.ParamType{smartcontract.StringType, smartcontract.IntegerType, smartcontract.Hash160Type},
ReturnType: smartcontract.BoolType,
Properties: smartcontract.HasStorage,
Name: "Contracto",
CodeVersion: "1.0.0",
Author: "Joe Random",
Email: "joe@example.com",
Description: "Test contract",
}
assert.Equal(t, hash.Hash160(script), contract.ScriptHash())
@ -37,3 +35,18 @@ func TestEncodeDecodeContractState(t *testing.T) {
assert.Equal(t, contract, contractDecoded)
assert.Equal(t, contract.ScriptHash(), contractDecoded.ScriptHash())
}
func TestContractStateProperties(t *testing.T) {
flaggedContract := ContractState{
Properties: smartcontract.HasStorage | smartcontract.HasDynamicInvoke | smartcontract.IsPayable,
}
nonFlaggedContract := ContractState{
ReturnType: smartcontract.BoolType,
}
assert.Equal(t, true, flaggedContract.HasStorage())
assert.Equal(t, true, flaggedContract.HasDynamicInvoke())
assert.Equal(t, true, flaggedContract.IsPayable())
assert.Equal(t, false, nonFlaggedContract.HasStorage())
assert.Equal(t, false, nonFlaggedContract.HasDynamicInvoke())
assert.Equal(t, false, nonFlaggedContract.IsPayable())
}

View file

@ -18,6 +18,17 @@ const (
ArrayType
)
// PropertyState represents contract properties (flags).
type PropertyState byte
// List of supported properties.
const (
NoProperties = 0
HasStorage PropertyState = 1 << iota
HasDynamicInvoke
IsPayable
)
// Parameter represents a smart contract parameter.
type Parameter struct {
// Type of the parameter