2020-03-19 15:52:37 +00:00
|
|
|
package native
|
|
|
|
|
|
|
|
import (
|
2020-09-23 08:48:31 +00:00
|
|
|
"errors"
|
|
|
|
|
2020-03-19 15:52:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
2020-06-17 10:57:54 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/io"
|
2020-09-23 08:48:31 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
2020-03-19 15:52:37 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
2020-06-17 10:57:54 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/emit"
|
2020-06-19 08:55:22 +00:00
|
|
|
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
2020-03-19 15:52:37 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Contracts is a set of registered native contracts.
|
|
|
|
type Contracts struct {
|
2020-03-25 10:00:11 +00:00
|
|
|
NEO *NEO
|
|
|
|
GAS *GAS
|
2020-06-15 18:13:32 +00:00
|
|
|
Policy *Policy
|
2020-09-18 13:26:36 +00:00
|
|
|
Oracle *Oracle
|
2020-10-01 15:17:09 +00:00
|
|
|
Designate *Designate
|
2020-04-22 20:00:18 +00:00
|
|
|
Contracts []interop.Contract
|
2020-06-17 10:57:54 +00:00
|
|
|
// persistScript is vm script which executes "onPersist" method of every native contract.
|
|
|
|
persistScript []byte
|
2020-09-23 08:48:31 +00:00
|
|
|
// postPersistScript is vm script which executes "postPersist" method of every native contract.
|
|
|
|
postPersistScript []byte
|
2020-03-19 15:52:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ByHash returns native contract with the specified hash.
|
2020-04-22 20:00:18 +00:00
|
|
|
func (cs *Contracts) ByHash(h util.Uint160) interop.Contract {
|
2020-03-19 15:52:37 +00:00
|
|
|
for _, ctr := range cs.Contracts {
|
|
|
|
if ctr.Metadata().Hash.Equals(h) {
|
|
|
|
return ctr
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-06-15 18:13:32 +00:00
|
|
|
// NewContracts returns new set of native contracts with new GAS, NEO and Policy
|
2020-04-22 20:00:18 +00:00
|
|
|
// contracts.
|
2020-03-19 15:52:37 +00:00
|
|
|
func NewContracts() *Contracts {
|
2020-04-22 20:00:18 +00:00
|
|
|
cs := new(Contracts)
|
|
|
|
|
|
|
|
gas := NewGAS()
|
|
|
|
neo := NewNEO()
|
|
|
|
neo.GAS = gas
|
|
|
|
gas.NEO = neo
|
|
|
|
|
|
|
|
cs.GAS = gas
|
|
|
|
cs.Contracts = append(cs.Contracts, gas)
|
|
|
|
cs.NEO = neo
|
|
|
|
cs.Contracts = append(cs.Contracts, neo)
|
2020-06-15 18:13:32 +00:00
|
|
|
|
|
|
|
policy := newPolicy()
|
|
|
|
cs.Policy = policy
|
|
|
|
cs.Contracts = append(cs.Contracts, policy)
|
2020-09-18 13:26:36 +00:00
|
|
|
|
|
|
|
oracle := newOracle()
|
|
|
|
oracle.GAS = gas
|
|
|
|
oracle.NEO = neo
|
|
|
|
cs.Oracle = oracle
|
|
|
|
cs.Contracts = append(cs.Contracts, oracle)
|
2020-10-01 15:17:09 +00:00
|
|
|
|
|
|
|
desig := newDesignate()
|
|
|
|
desig.NEO = neo
|
|
|
|
cs.Designate = desig
|
|
|
|
cs.Oracle.Desig = desig
|
|
|
|
cs.Contracts = append(cs.Contracts, desig)
|
|
|
|
|
2020-04-22 20:00:18 +00:00
|
|
|
return cs
|
2020-06-17 10:57:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetPersistScript returns VM script calling "onPersist" method of every native contract.
|
|
|
|
func (cs *Contracts) GetPersistScript() []byte {
|
|
|
|
if cs.persistScript != nil {
|
|
|
|
return cs.persistScript
|
|
|
|
}
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
for i := range cs.Contracts {
|
|
|
|
md := cs.Contracts[i].Metadata()
|
2020-09-05 07:50:08 +00:00
|
|
|
// Not every contract is persisted:
|
|
|
|
// https://github.com/neo-project/neo/blob/master/src/neo/Ledger/Blockchain.cs#L90
|
2020-10-01 15:17:09 +00:00
|
|
|
if md.ContractID == policyContractID || md.ContractID == oracleContractID || md.ContractID == designateContractID {
|
2020-09-05 07:50:08 +00:00
|
|
|
continue
|
|
|
|
}
|
2020-06-19 08:55:22 +00:00
|
|
|
emit.Int(w.BinWriter, 0)
|
|
|
|
emit.Opcode(w.BinWriter, opcode.NEWARRAY)
|
|
|
|
emit.String(w.BinWriter, "onPersist")
|
|
|
|
emit.AppCall(w.BinWriter, md.Hash)
|
2020-08-10 08:52:32 +00:00
|
|
|
emit.Opcode(w.BinWriter, opcode.DROP)
|
2020-06-17 10:57:54 +00:00
|
|
|
}
|
|
|
|
cs.persistScript = w.Bytes()
|
|
|
|
return cs.persistScript
|
2020-03-19 15:52:37 +00:00
|
|
|
}
|
2020-09-23 08:48:31 +00:00
|
|
|
|
|
|
|
// GetPostPersistScript returns VM script calling "postPersist" method of some native contracts.
|
|
|
|
func (cs *Contracts) GetPostPersistScript() []byte {
|
|
|
|
if cs.postPersistScript != nil {
|
|
|
|
return cs.postPersistScript
|
|
|
|
}
|
|
|
|
w := io.NewBufBinWriter()
|
|
|
|
for i := range cs.Contracts {
|
|
|
|
md := cs.Contracts[i].Metadata()
|
|
|
|
// Not every contract is persisted:
|
|
|
|
// https://github.com/neo-project/neo/blob/master/src/neo/Ledger/Blockchain.cs#L103
|
2020-10-01 15:17:09 +00:00
|
|
|
if md.ContractID == policyContractID || md.ContractID == gasContractID || md.ContractID == designateContractID {
|
2020-09-23 08:48:31 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
emit.Int(w.BinWriter, 0)
|
|
|
|
emit.Opcode(w.BinWriter, opcode.NEWARRAY)
|
|
|
|
emit.String(w.BinWriter, "postPersist")
|
|
|
|
emit.AppCall(w.BinWriter, md.Hash)
|
|
|
|
emit.Opcode(w.BinWriter, opcode.DROP)
|
|
|
|
}
|
|
|
|
cs.postPersistScript = w.Bytes()
|
|
|
|
return cs.postPersistScript
|
|
|
|
}
|
|
|
|
|
|
|
|
func postPersistBase(ic *interop.Context) error {
|
|
|
|
if ic.Trigger != trigger.System {
|
|
|
|
return errors.New("'postPersist' should be trigered by system")
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|