2018-04-16 20:15:30 +00:00
|
|
|
package core
|
|
|
|
|
|
|
|
import (
|
2019-09-30 16:52:16 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/core/storage"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/io"
|
2018-04-16 20:15:30 +00:00
|
|
|
"github.com/CityOfZion/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/CityOfZion/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
2019-09-30 16:52:16 +00:00
|
|
|
// Contracts is a mapping between scripthash and ContractState.
|
|
|
|
type Contracts map[util.Uint160]*ContractState
|
|
|
|
|
2018-04-16 20:15:30 +00:00
|
|
|
// ContractState holds information about a smart contract in the NEO blockchain.
|
|
|
|
type ContractState struct {
|
2019-10-10 14:56:58 +00:00
|
|
|
Script []byte
|
|
|
|
ParamList []smartcontract.ParamType
|
|
|
|
ReturnType smartcontract.ParamType
|
|
|
|
Properties smartcontract.PropertyState
|
|
|
|
Name string
|
|
|
|
CodeVersion string
|
|
|
|
Author string
|
|
|
|
Email string
|
|
|
|
Description string
|
2018-04-16 20:15:30 +00:00
|
|
|
|
|
|
|
scriptHash util.Uint160
|
|
|
|
}
|
2019-09-30 16:52:16 +00:00
|
|
|
|
|
|
|
// commit flushes all contracts to the given storage.Batch.
|
|
|
|
func (a Contracts) commit(b storage.Batch) error {
|
|
|
|
buf := io.NewBufBinWriter()
|
|
|
|
for hash, contract := range a {
|
|
|
|
contract.EncodeBinary(buf.BinWriter)
|
|
|
|
if buf.Err != nil {
|
|
|
|
return buf.Err
|
|
|
|
}
|
|
|
|
key := storage.AppendPrefix(storage.STContract, hash.Bytes())
|
|
|
|
b.Put(key, buf.Bytes())
|
|
|
|
buf.Reset()
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DecodeBinary implements Serializable interface.
|
|
|
|
func (a *ContractState) DecodeBinary(br *io.BinReader) {
|
|
|
|
a.Script = br.ReadBytes()
|
|
|
|
paramBytes := br.ReadBytes()
|
|
|
|
a.ParamList = make([]smartcontract.ParamType, len(paramBytes))
|
|
|
|
for k := range paramBytes {
|
|
|
|
a.ParamList[k] = smartcontract.ParamType(paramBytes[k])
|
|
|
|
}
|
|
|
|
br.ReadLE(&a.ReturnType)
|
2019-10-10 14:56:58 +00:00
|
|
|
br.ReadLE(&a.Properties)
|
2019-09-30 16:52:16 +00:00
|
|
|
a.Name = br.ReadString()
|
|
|
|
a.CodeVersion = br.ReadString()
|
|
|
|
a.Author = br.ReadString()
|
|
|
|
a.Email = br.ReadString()
|
|
|
|
a.Description = br.ReadString()
|
|
|
|
a.createHash()
|
|
|
|
}
|
|
|
|
|
|
|
|
// EncodeBinary implements Serializable interface.
|
|
|
|
func (a *ContractState) EncodeBinary(bw *io.BinWriter) {
|
|
|
|
bw.WriteBytes(a.Script)
|
|
|
|
bw.WriteVarUint(uint64(len(a.ParamList)))
|
|
|
|
for k := range a.ParamList {
|
|
|
|
bw.WriteLE(a.ParamList[k])
|
|
|
|
}
|
|
|
|
bw.WriteLE(a.ReturnType)
|
2019-10-10 14:56:58 +00:00
|
|
|
bw.WriteLE(a.Properties)
|
2019-09-30 16:52:16 +00:00
|
|
|
bw.WriteString(a.Name)
|
|
|
|
bw.WriteString(a.CodeVersion)
|
|
|
|
bw.WriteString(a.Author)
|
|
|
|
bw.WriteString(a.Email)
|
|
|
|
bw.WriteString(a.Description)
|
|
|
|
}
|
|
|
|
|
2019-10-11 10:11:54 +00:00
|
|
|
// putContractStateIntoStore puts given contract state into the given store.
|
|
|
|
func putContractStateIntoStore(s storage.Store, cs *ContractState) error {
|
|
|
|
buf := io.NewBufBinWriter()
|
|
|
|
cs.EncodeBinary(buf.BinWriter)
|
|
|
|
if buf.Err != nil {
|
|
|
|
return buf.Err
|
|
|
|
}
|
|
|
|
key := storage.AppendPrefix(storage.STContract, cs.ScriptHash().Bytes())
|
|
|
|
return s.Put(key, buf.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
// deleteContractStateInStore deletes given contract state in the given store.
|
|
|
|
func deleteContractStateInStore(s storage.Store, hash util.Uint160) error {
|
|
|
|
key := storage.AppendPrefix(storage.STContract, hash.Bytes())
|
|
|
|
return s.Delete(key)
|
|
|
|
}
|
|
|
|
|
2019-09-30 16:52:16 +00:00
|
|
|
// ScriptHash returns a contract script hash.
|
|
|
|
func (a *ContractState) ScriptHash() util.Uint160 {
|
|
|
|
if a.scriptHash.Equals(util.Uint160{}) {
|
|
|
|
a.createHash()
|
|
|
|
}
|
|
|
|
return a.scriptHash
|
|
|
|
}
|
|
|
|
|
|
|
|
// createHash creates contract script hash.
|
|
|
|
func (a *ContractState) createHash() {
|
|
|
|
a.scriptHash = hash.Hash160(a.Script)
|
|
|
|
}
|
2019-10-10 14:56:58 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|