neoneo-go/pkg/core/native/native_gas.go
Anna Shaleva 33c971b0e4 core: add InitializeCache method to Contract interface
Make the contracts cache initialization unified. The order of cache
iniitialization is not important and Nottary contract is added to the
bc.contracts.Contracts wrt P2PSigExtensions setting, thus no functional
changes, just refactoring for future applications.

Signed-off-by: Anna Shaleva <shaleva.ann@nspcc.ru>
2023-04-26 12:57:48 +03:00

156 lines
4.3 KiB
Go

package native
import (
"errors"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/native/nativenames"
"github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/util"
)
// GAS represents GAS native contract.
type GAS struct {
nep17TokenNative
NEO *NEO
// Notary is a native Notary contract. It is set only when P2PSigExtensions are on.
Notary *Notary
initialSupply int64
p2pSigExtensionsEnabled bool
}
const gasContractID = -6
// GASFactor is a divisor for finding GAS integral value.
const GASFactor = NEOTotalSupply
// newGAS returns GAS native contract.
func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
g := &GAS{
initialSupply: init,
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
}
defer g.UpdateHash()
nep17 := newNEP17Native(nativenames.Gas, gasContractID)
nep17.symbol = "GAS"
nep17.decimals = 8
nep17.factor = GASFactor
nep17.incBalance = g.increaseBalance
nep17.balFromBytes = g.balanceFromBytes
g.nep17TokenNative = *nep17
return g
}
func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.StorageItem, amount *big.Int, checkBal *big.Int) (func(), error) {
acc, err := state.NEP17BalanceFromBytes(*si)
if err != nil {
return nil, err
}
if sign := amount.Sign(); sign == 0 {
// Requested self-transfer amount can be higher than actual balance.
if checkBal != nil && acc.Balance.Cmp(checkBal) < 0 {
err = errors.New("insufficient funds")
}
return nil, err
} else if sign == -1 && acc.Balance.CmpAbs(amount) == -1 {
return nil, errors.New("insufficient funds")
}
acc.Balance.Add(&acc.Balance, amount)
if acc.Balance.Sign() != 0 {
*si = acc.Bytes(nil)
} else {
*si = nil
}
return nil, nil
}
func (g *GAS) balanceFromBytes(si *state.StorageItem) (*big.Int, error) {
acc, err := state.NEP17BalanceFromBytes(*si)
if err != nil {
return nil, err
}
return &acc.Balance, err
}
// Initialize initializes a GAS contract.
func (g *GAS) Initialize(ic *interop.Context) error {
if err := g.nep17TokenNative.Initialize(ic); err != nil {
return err
}
_, totalSupply := g.nep17TokenNative.getTotalSupply(ic.DAO)
if totalSupply.Sign() != 0 {
return errors.New("already initialized")
}
h, err := getStandbyValidatorsHash(ic)
if err != nil {
return err
}
g.mint(ic, h, big.NewInt(g.initialSupply), false)
return nil
}
// InitializeCache implements the Contract interface.
func (g *GAS) InitializeCache(blockHeight uint32, d *dao.Simple) error {
return nil
}
// OnPersist implements the Contract interface.
func (g *GAS) OnPersist(ic *interop.Context) error {
if len(ic.Block.Transactions) == 0 {
return nil
}
for _, tx := range ic.Block.Transactions {
absAmount := big.NewInt(tx.SystemFee + tx.NetworkFee)
g.burn(ic, tx.Sender(), absAmount)
}
validators := g.NEO.GetNextBlockValidatorsInternal(ic.DAO)
primary := validators[ic.Block.PrimaryIndex].GetScriptHash()
var netFee int64
for _, tx := range ic.Block.Transactions {
netFee += tx.NetworkFee
if g.p2pSigExtensionsEnabled {
// Reward for NotaryAssisted attribute will be minted to designated notary nodes
// by Notary contract.
attrs := tx.GetAttributes(transaction.NotaryAssistedT)
if len(attrs) != 0 {
na := attrs[0].Value.(*transaction.NotaryAssisted)
netFee -= (int64(na.NKeys) + 1) * g.Notary.GetNotaryServiceFeePerKey(ic.DAO)
}
}
}
g.mint(ic, primary, big.NewInt(int64(netFee)), false)
return nil
}
// PostPersist implements the Contract interface.
func (g *GAS) PostPersist(ic *interop.Context) error {
return nil
}
// BalanceOf returns native GAS token balance for the acc.
func (g *GAS) BalanceOf(d *dao.Simple, acc util.Uint160) *big.Int {
return g.balanceOfInternal(d, acc)
}
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, error) {
cfg := ic.Chain.GetConfig()
committee, err := keys.NewPublicKeysFromStrings(cfg.StandbyCommittee)
if err != nil {
return util.Uint160{}, err
}
s, err := smartcontract.CreateDefaultMultiSigRedeemScript(committee[:cfg.GetNumOfCNs(0)])
if err != nil {
return util.Uint160{}, err
}
return hash.Hash160(s), nil
}