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

View file

@ -16,14 +16,12 @@ type ContractState struct {
Script []byte Script []byte
ParamList []smartcontract.ParamType ParamList []smartcontract.ParamType
ReturnType smartcontract.ParamType ReturnType smartcontract.ParamType
Properties []byte Properties smartcontract.PropertyState
Name string Name string
CodeVersion string CodeVersion string
Author string Author string
Email string Email string
Description string Description string
HasStorage bool
HasDynamicInvoke bool
scriptHash util.Uint160 scriptHash util.Uint160
} }
@ -52,14 +50,12 @@ func (a *ContractState) DecodeBinary(br *io.BinReader) {
a.ParamList[k] = smartcontract.ParamType(paramBytes[k]) a.ParamList[k] = smartcontract.ParamType(paramBytes[k])
} }
br.ReadLE(&a.ReturnType) br.ReadLE(&a.ReturnType)
a.Properties = br.ReadBytes() br.ReadLE(&a.Properties)
a.Name = br.ReadString() a.Name = br.ReadString()
a.CodeVersion = br.ReadString() a.CodeVersion = br.ReadString()
a.Author = br.ReadString() a.Author = br.ReadString()
a.Email = br.ReadString() a.Email = br.ReadString()
a.Description = br.ReadString() a.Description = br.ReadString()
br.ReadLE(&a.HasStorage)
br.ReadLE(&a.HasDynamicInvoke)
a.createHash() a.createHash()
} }
@ -71,14 +67,12 @@ func (a *ContractState) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(a.ParamList[k]) bw.WriteLE(a.ParamList[k])
} }
bw.WriteLE(a.ReturnType) bw.WriteLE(a.ReturnType)
bw.WriteBytes(a.Properties) bw.WriteLE(a.Properties)
bw.WriteString(a.Name) bw.WriteString(a.Name)
bw.WriteString(a.CodeVersion) bw.WriteString(a.CodeVersion)
bw.WriteString(a.Author) bw.WriteString(a.Author)
bw.WriteString(a.Email) bw.WriteString(a.Email)
bw.WriteString(a.Description) bw.WriteString(a.Description)
bw.WriteLE(a.HasStorage)
bw.WriteLE(a.HasDynamicInvoke)
} }
// ScriptHash returns a contract script hash. // ScriptHash returns a contract script hash.
@ -93,3 +87,18 @@ func (a *ContractState) ScriptHash() util.Uint160 {
func (a *ContractState) createHash() { func (a *ContractState) createHash() {
a.scriptHash = hash.Hash160(a.Script) 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

@ -16,14 +16,12 @@ func TestEncodeDecodeContractState(t *testing.T) {
Script: script, Script: script,
ParamList: []smartcontract.ParamType{smartcontract.StringType, smartcontract.IntegerType, smartcontract.Hash160Type}, ParamList: []smartcontract.ParamType{smartcontract.StringType, smartcontract.IntegerType, smartcontract.Hash160Type},
ReturnType: smartcontract.BoolType, ReturnType: smartcontract.BoolType,
Properties: []byte("smth"), Properties: smartcontract.HasStorage,
Name: "Contracto", Name: "Contracto",
CodeVersion: "1.0.0", CodeVersion: "1.0.0",
Author: "Joe Random", Author: "Joe Random",
Email: "joe@example.com", Email: "joe@example.com",
Description: "Test contract", Description: "Test contract",
HasStorage: true,
HasDynamicInvoke: false,
} }
assert.Equal(t, hash.Hash160(script), contract.ScriptHash()) 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, contractDecoded)
assert.Equal(t, contract.ScriptHash(), contractDecoded.ScriptHash()) 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 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. // Parameter represents a smart contract parameter.
type Parameter struct { type Parameter struct {
// Type of the parameter // Type of the parameter