2020-03-25 10:00:11 +00:00
|
|
|
package native
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/core/state"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/smartcontract"
|
|
|
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
|
|
|
)
|
|
|
|
|
|
|
|
// GAS represents GAS native contract.
|
|
|
|
type GAS struct {
|
|
|
|
nep5TokenNative
|
|
|
|
NEO *NEO
|
|
|
|
}
|
|
|
|
|
2020-07-22 16:03:05 +00:00
|
|
|
const gasName = "GAS"
|
2020-06-10 11:23:25 +00:00
|
|
|
const gasContractID = -2
|
2020-03-25 10:00:11 +00:00
|
|
|
|
2020-04-22 20:00:18 +00:00
|
|
|
// GASFactor is a divisor for finding GAS integral value.
|
|
|
|
const GASFactor = NEOTotalSupply
|
|
|
|
const initialGAS = 30000000
|
|
|
|
|
2020-10-02 10:50:56 +00:00
|
|
|
// newGAS returns GAS native contract.
|
|
|
|
func newGAS() *GAS {
|
2020-05-14 18:01:56 +00:00
|
|
|
g := &GAS{}
|
2020-07-22 16:03:05 +00:00
|
|
|
nep5 := newNEP5Native(gasName)
|
2020-03-25 10:00:11 +00:00
|
|
|
nep5.symbol = "gas"
|
|
|
|
nep5.decimals = 8
|
2020-04-22 20:00:18 +00:00
|
|
|
nep5.factor = GASFactor
|
2020-06-17 10:57:54 +00:00
|
|
|
nep5.onPersist = chainOnPersist(nep5.OnPersist, g.OnPersist)
|
2020-05-14 18:01:56 +00:00
|
|
|
nep5.incBalance = g.increaseBalance
|
2020-06-10 11:23:25 +00:00
|
|
|
nep5.ContractID = gasContractID
|
2020-03-25 10:00:11 +00:00
|
|
|
|
2020-05-14 18:01:56 +00:00
|
|
|
g.nep5TokenNative = *nep5
|
2020-03-25 10:00:11 +00:00
|
|
|
|
2020-06-17 10:57:54 +00:00
|
|
|
onp := g.Methods["onPersist"]
|
|
|
|
onp.Func = getOnPersistWrapper(g.onPersist)
|
|
|
|
g.Methods["onPersist"] = onp
|
|
|
|
|
2020-03-25 10:00:11 +00:00
|
|
|
return g
|
|
|
|
}
|
|
|
|
|
2020-04-23 18:28:37 +00:00
|
|
|
func (g *GAS) increaseBalance(_ *interop.Context, _ util.Uint160, si *state.StorageItem, amount *big.Int) error {
|
|
|
|
acc, err := state.NEP5BalanceStateFromBytes(si.Value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-03-25 10:00:11 +00:00
|
|
|
if sign := amount.Sign(); sign == 0 {
|
|
|
|
return nil
|
2020-04-23 18:28:37 +00:00
|
|
|
} else if sign == -1 && acc.Balance.Cmp(new(big.Int).Neg(amount)) == -1 {
|
2020-03-25 10:00:11 +00:00
|
|
|
return errors.New("insufficient funds")
|
|
|
|
}
|
2020-04-23 18:28:37 +00:00
|
|
|
acc.Balance.Add(&acc.Balance, amount)
|
2020-06-23 18:57:05 +00:00
|
|
|
if acc.Balance.Sign() != 0 {
|
|
|
|
si.Value = acc.Bytes()
|
|
|
|
} else {
|
|
|
|
si.Value = nil
|
|
|
|
}
|
2020-03-25 10:00:11 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize initializes GAS contract.
|
|
|
|
func (g *GAS) Initialize(ic *interop.Context) error {
|
2020-04-22 20:00:18 +00:00
|
|
|
if err := g.nep5TokenNative.Initialize(ic); err != nil {
|
2020-03-25 10:00:11 +00:00
|
|
|
return err
|
|
|
|
}
|
2020-08-03 11:31:42 +00:00
|
|
|
if g.nep5TokenNative.getTotalSupply(ic.DAO).Sign() != 0 {
|
2020-04-22 20:00:18 +00:00
|
|
|
return errors.New("already initialized")
|
2020-03-25 10:00:11 +00:00
|
|
|
}
|
2020-08-10 14:51:46 +00:00
|
|
|
h, err := getStandbyValidatorsHash(ic)
|
2020-03-25 10:00:11 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2020-04-22 20:00:18 +00:00
|
|
|
g.mint(ic, h, big.NewInt(initialGAS*GASFactor))
|
|
|
|
return nil
|
2020-03-25 10:00:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// OnPersist implements Contract interface.
|
|
|
|
func (g *GAS) OnPersist(ic *interop.Context) error {
|
2020-06-18 18:51:29 +00:00
|
|
|
if len(ic.Block.Transactions) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
2020-05-08 17:54:24 +00:00
|
|
|
for _, tx := range ic.Block.Transactions {
|
2020-06-23 14:15:35 +00:00
|
|
|
absAmount := big.NewInt(tx.SystemFee + tx.NetworkFee)
|
2020-07-29 16:57:38 +00:00
|
|
|
g.burn(ic, tx.Sender(), absAmount)
|
2020-05-08 17:54:24 +00:00
|
|
|
}
|
2020-08-28 07:24:54 +00:00
|
|
|
validators := g.NEO.GetNextBlockValidatorsInternal()
|
2020-05-08 17:54:24 +00:00
|
|
|
primary := validators[ic.Block.ConsensusData.PrimaryIndex].GetScriptHash()
|
2020-06-23 14:15:35 +00:00
|
|
|
var netFee int64
|
2020-05-08 17:54:24 +00:00
|
|
|
for _, tx := range ic.Block.Transactions {
|
|
|
|
netFee += tx.NetworkFee
|
|
|
|
}
|
|
|
|
g.mint(ic, primary, big.NewInt(int64(netFee)))
|
2020-04-22 20:00:18 +00:00
|
|
|
return nil
|
2020-03-25 10:00:11 +00:00
|
|
|
}
|
|
|
|
|
2020-08-10 14:51:46 +00:00
|
|
|
func getStandbyValidatorsHash(ic *interop.Context) (util.Uint160, error) {
|
2020-08-10 15:58:11 +00:00
|
|
|
s, err := smartcontract.CreateDefaultMultiSigRedeemScript(ic.Chain.GetStandByValidators())
|
2020-03-25 10:00:11 +00:00
|
|
|
if err != nil {
|
2020-08-10 14:51:46 +00:00
|
|
|
return util.Uint160{}, err
|
2020-03-25 10:00:11 +00:00
|
|
|
}
|
2020-08-10 14:51:46 +00:00
|
|
|
return hash.Hash160(s), nil
|
2020-03-25 10:00:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func chainOnPersist(fs ...func(*interop.Context) error) func(*interop.Context) error {
|
|
|
|
return func(ic *interop.Context) error {
|
|
|
|
for i := range fs {
|
|
|
|
if fs[i] != nil {
|
|
|
|
if err := fs[i](ic); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|