package native import ( "math/big" "strings" "github.com/tutus-one/tutus-chain/pkg/config" "github.com/tutus-one/tutus-chain/pkg/core/dao" "github.com/tutus-one/tutus-chain/pkg/core/interop" "github.com/tutus-one/tutus-chain/pkg/core/interop/interopnames" "github.com/tutus-one/tutus-chain/pkg/core/native/nativenames" "github.com/tutus-one/tutus-chain/pkg/core/native/noderoles" "github.com/tutus-one/tutus-chain/pkg/core/state" "github.com/tutus-one/tutus-chain/pkg/core/transaction" "github.com/tutus-one/tutus-chain/pkg/crypto/keys" "github.com/tutus-one/tutus-chain/pkg/io" "github.com/tutus-one/tutus-chain/pkg/util" "github.com/tutus-one/tutus-chain/pkg/vm/emit" ) // Native contract interfaces sufficient for Blockchain functioning and // cross-native interaction. type ( // IManagement is an interface required from native ContractManagement // contract for interaction with Blockchain and other native contracts. IManagement interface { interop.Contract GetNEP11Contracts(d *dao.Simple) []util.Uint160 GetNEP17Contracts(d *dao.Simple) []util.Uint160 } // INEO is an interface required from native NeoToken contract for // interaction with Blockchain and other native contracts. INEO interface { interop.Contract GetCommitteeAddress(d *dao.Simple) util.Uint160 GetNextBlockValidatorsInternal(d *dao.Simple) keys.PublicKeys BalanceOf(d *dao.Simple, acc util.Uint160) (*big.Int, uint32) CalculateBonus(ic *interop.Context, acc util.Uint160, endHeight uint32) (*big.Int, error) GetCommitteeMembers(d *dao.Simple) keys.PublicKeys ComputeNextBlockValidators(d *dao.Simple) keys.PublicKeys GetCandidates(d *dao.Simple) ([]state.Validator, error) // Methods required for proper cross-native communication. CheckCommittee(ic *interop.Context) bool RevokeVotes(ic *interop.Context, h util.Uint160) error } // IGAS is an interface required from native GasToken contract for // interaction with Blockchain and other native contracts. IGAS interface { interop.Contract BalanceOf(d *dao.Simple, acc util.Uint160) *big.Int // Methods required for proper cross-native communication. Burn(ic *interop.Context, h util.Uint160, amount *big.Int) Mint(ic *interop.Context, h util.Uint160, amount *big.Int, callOnPayment bool) } // IPolicy is an interface required from native PolicyContract contract for // interaction with Blockchain and other native contracts. IPolicy interface { interop.Contract // GetStoragePriceInternal returns the current storage price in picoGAS units. GetStoragePriceInternal(d *dao.Simple) int64 GetMaxVerificationGas(d *dao.Simple) int64 // GetExecFeeFactorInternal returns the current execution fee factor in picoGAS units. GetExecFeeFactorInternal(d *dao.Simple) int64 GetMaxTraceableBlocksInternal(d *dao.Simple) uint32 GetMillisecondsPerBlockInternal(d *dao.Simple) uint32 GetMaxValidUntilBlockIncrementFromCache(d *dao.Simple) uint32 GetAttributeFeeInternal(d *dao.Simple, attrType transaction.AttrType) int64 CheckPolicy(d *dao.Simple, tx *transaction.Transaction) error GetFeePerByteInternal(d *dao.Simple) int64 // Methods required for proper cross-native communication. BlockAccountInternal(ic *interop.Context, hash util.Uint160) bool GetMaxValidUntilBlockIncrementInternal(ic *interop.Context) uint32 CleanWhitelist(ic *interop.Context, cs *state.Contract) error interop.PolicyChecker } // IOracle is an interface required from native OracleContract contract for // interaction with Blockchain and other native contracts. IOracle interface { interop.Contract GetOracleResponseScript() []byte GetRequests(d *dao.Simple) (map[uint64]*state.OracleRequest, error) GetScriptHash(d *dao.Simple) (util.Uint160, error) GetRequestInternal(d *dao.Simple, id uint64) (*state.OracleRequest, error) SetService(o OracleService) } // IDesignate is an interface required from native RoleManagement contract // for interaction with Blockchain and other native contracts. IDesignate interface { interop.Contract GetDesignatedByRole(d *dao.Simple, r noderoles.Role, index uint32) (keys.PublicKeys, uint32, error) GetLastDesignatedHash(d *dao.Simple, r noderoles.Role) (util.Uint160, error) SetOracleService(o OracleService) SetNotaryService(n NotaryService) SetStateRootService(s StateRootService) } // INotary is an interface required from native Notary contract for // interaction with Blockchain and other native contracts. INotary interface { interop.Contract BalanceOf(dao *dao.Simple, acc util.Uint160) *big.Int ExpirationOf(dao *dao.Simple, acc util.Uint160) uint32 GetMaxNotValidBeforeDelta(dao *dao.Simple) uint32 } // IPersonToken is an interface required from native PersonToken contract // for interaction with Blockchain and other native contracts. IPersonToken interface { interop.Contract GetTokenByOwner(d *dao.Simple, owner util.Uint160) (*state.PersonToken, error) GetTokenByIDPublic(d *dao.Simple, tokenID uint64) (*state.PersonToken, error) TokenExists(d *dao.Simple, owner util.Uint160) bool GetAttribute(d *dao.Simple, tokenID uint64, key string) (*state.Attribute, error) } // IRoleRegistry is an interface required from native RoleRegistry contract // for interaction with Blockchain and other native contracts. // RoleRegistry provides democratic governance for Tutus, replacing NEO.CheckCommittee(). IRoleRegistry interface { interop.Contract // CheckCommittee returns true if caller has COMMITTEE role. // This replaces NEO.CheckCommittee() for Tutus democratic governance. CheckCommittee(ic *interop.Context) bool // HasRoleInternal checks if address has role (includes hierarchy). HasRoleInternal(d *dao.Simple, address util.Uint160, roleID uint64, blockHeight uint32) bool // HasPermissionInternal checks if address has permission via roles. HasPermissionInternal(d *dao.Simple, address util.Uint160, resource, action string, scope state.Scope, blockHeight uint32) bool } ) // Contracts is a convenient wrapper around an arbitrary set of native contracts // providing common helper contract accessors. type Contracts struct { List []interop.Contract // persistScript is a vm script which executes "onPersist" method of every native contract. persistScript []byte // postPersistScript is a vm script which executes "postPersist" method of every native contract. postPersistScript []byte } // NewContracts initializes a wrapper around the provided set of native // contracts. func NewContracts(natives []interop.Contract) *Contracts { return &Contracts{ List: natives, } } // ByHash returns a native contract with the specified hash. func (cs *Contracts) ByHash(h util.Uint160) interop.Contract { for _, ctr := range cs.List { if ctr.Metadata().Hash.Equals(h) { return ctr } } return nil } // ByName returns a native contract with the specified name. func (cs *Contracts) ByName(name string) interop.Contract { name = strings.ToLower(name) for _, ctr := range cs.List { if strings.ToLower(ctr.Metadata().Name) == name { return ctr } } return nil } // GetPersistScript returns a VM script calling "onPersist" syscall for native contracts. func (cs *Contracts) GetPersistScript() []byte { if cs.persistScript != nil { return cs.persistScript } w := io.NewBufBinWriter() emit.Syscall(w.BinWriter, interopnames.SystemContractNativeOnPersist) cs.persistScript = w.Bytes() return cs.persistScript } // GetPostPersistScript returns a VM script calling "postPersist" syscall for native contracts. func (cs *Contracts) GetPostPersistScript() []byte { if cs.postPersistScript != nil { return cs.postPersistScript } w := io.NewBufBinWriter() emit.Syscall(w.BinWriter, interopnames.SystemContractNativePostPersist) cs.postPersistScript = w.Bytes() return cs.postPersistScript } // Management returns native IManagement implementation. It panics if there's no // contract with proper name in cs. func (cs *Contracts) Management() IManagement { return cs.ByName(nativenames.Management).(IManagement) } // NEO returns native INEO contract implementation. It panics if there's no // contract with proper name in cs. func (cs *Contracts) NEO() INEO { return cs.ByName(nativenames.Neo).(INEO) } // GAS returns native IGAS contract implementation. It panics if there's no // contract with proper name in cs. func (cs *Contracts) GAS() IGAS { return cs.ByName(nativenames.Gas).(IGAS) } // Designate returns native IDesignate contract implementation. It panics if // there's no contract with proper name in cs. func (cs *Contracts) Designate() IDesignate { return cs.ByName(nativenames.Designation).(IDesignate) } // Policy returns native IPolicy contract implementation. It panics if there's // no contract with proper name in cs. func (cs *Contracts) Policy() IPolicy { return cs.ByName(nativenames.Policy).(IPolicy) } // Oracle returns native IOracle contract implementation. It returns nil if // there's no contract with proper name in cs. func (cs *Contracts) Oracle() IOracle { res := cs.ByName(nativenames.Oracle) // Oracle contract is optional. if res != nil { return res.(IOracle) } return nil } // Notary returns native INotary contract implementation. It returns nil if // there's no contract with proper name in cs. func (cs *Contracts) Notary() INotary { res := cs.ByName(nativenames.Notary) // Notary contract is optional. if res != nil { return res.(INotary) } return nil } // PersonToken returns native IPersonToken contract implementation. It panics if // there's no contract with proper name in cs. func (cs *Contracts) PersonToken() IPersonToken { return cs.ByName(nativenames.PersonToken).(IPersonToken) } // RoleRegistry returns native IRoleRegistry contract implementation. It panics if // there's no contract with proper name in cs. func (cs *Contracts) RoleRegistry() IRoleRegistry { return cs.ByName(nativenames.RoleRegistry).(IRoleRegistry) } // NewDefaultContracts returns a new set of default native contracts. func NewDefaultContracts(cfg config.ProtocolConfiguration) []interop.Contract { mgmt := NewManagement() s := newStd() c := newCrypto() ledger := NewLedger() gas := newGAS(int64(cfg.InitialGASSupply)) neo := newNEO(cfg) policy := newPolicy() neo.GAS = gas neo.Policy = policy gas.NEO = neo gas.Policy = policy mgmt.NEO = neo mgmt.Policy = policy policy.NEO = neo ledger.Policy = policy desig := NewDesignate(cfg.Genesis.Roles) desig.NEO = neo oracle := newOracle() oracle.GAS = gas oracle.NEO = neo oracle.Desig = desig notary := newNotary() notary.GAS = gas notary.NEO = neo notary.Desig = desig notary.Policy = policy treasury := newTreasury() treasury.NEO = neo personToken := newPersonToken() personToken.NEO = neo // Parse TutusCommittee addresses from config var tutusCommittee []util.Uint160 for _, addrStr := range cfg.TutusCommittee { addr, err := util.Uint160DecodeStringLE(addrStr) if err != nil { // Try parsing as hex (BE format) addr, err = util.Uint160DecodeStringBE(addrStr) if err != nil { continue // Skip invalid addresses } } tutusCommittee = append(tutusCommittee, addr) } roleRegistry := newRoleRegistry(tutusCommittee) roleRegistry.NEO = neo // Set RoleRegistry on PersonToken for cross-contract integration personToken.RoleRegistry = roleRegistry return []interop.Contract{ mgmt, s, c, ledger, neo, gas, policy, desig, oracle, notary, treasury, personToken, roleRegistry, } }