core: fix GAS distribution to primary node when notary enabled
Close #2310.
This commit is contained in:
parent
b43335e591
commit
8c6de35ec2
3 changed files with 113 additions and 4 deletions
|
@ -75,7 +75,7 @@ func NewContracts(cfg config.ProtocolConfiguration) *Contracts {
|
|||
cs.Ledger = ledger
|
||||
cs.Contracts = append(cs.Contracts, ledger)
|
||||
|
||||
gas := newGAS(int64(cfg.InitialGASSupply))
|
||||
gas := newGAS(int64(cfg.InitialGASSupply), cfg.P2PSigExtensions)
|
||||
neo := newNEO()
|
||||
neo.GAS = gas
|
||||
gas.NEO = neo
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"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/smartcontract"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
|
@ -18,7 +19,8 @@ type GAS struct {
|
|||
nep17TokenNative
|
||||
NEO *NEO
|
||||
|
||||
initialSupply int64
|
||||
initialSupply int64
|
||||
p2pSigExtensionsEnabled bool
|
||||
}
|
||||
|
||||
const gasContractID = -6
|
||||
|
@ -27,8 +29,11 @@ const gasContractID = -6
|
|||
const GASFactor = NEOTotalSupply
|
||||
|
||||
// newGAS returns GAS native contract.
|
||||
func newGAS(init int64) *GAS {
|
||||
g := &GAS{initialSupply: init}
|
||||
func newGAS(init int64, p2pSigExtensionsEnabled bool) *GAS {
|
||||
g := &GAS{
|
||||
initialSupply: init,
|
||||
p2pSigExtensionsEnabled: p2pSigExtensionsEnabled,
|
||||
}
|
||||
defer g.UpdateHash()
|
||||
|
||||
nep17 := newNEP17Native(nativenames.Gas, gasContractID)
|
||||
|
@ -105,6 +110,15 @@ func (g *GAS) OnPersist(ic *interop.Context) error {
|
|||
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) * transaction.NotaryServiceFeePerKey
|
||||
}
|
||||
}
|
||||
}
|
||||
g.mint(ic, primary, big.NewInt(int64(netFee)), false)
|
||||
return nil
|
||||
|
|
|
@ -4,10 +4,17 @@ import (
|
|||
"math/big"
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neo-go/internal/testchain"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/interop"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/native/noderoles"
|
||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
|
||||
"github.com/nspcc-dev/neo-go/pkg/smartcontract/trigger"
|
||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
|
||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
|
@ -52,3 +59,91 @@ func TestGAS_Roundtrip(t *testing.T) {
|
|||
require.Equal(t, bc.BlockHeight(), updatedHeight)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGAS_RewardWithP2PSigExtensionsEnabled(t *testing.T) {
|
||||
chain := newTestChain(t)
|
||||
notaryHash := chain.contracts.Notary.Hash
|
||||
gasHash := chain.contracts.GAS.Hash
|
||||
signer := testchain.MultisigScriptHash()
|
||||
var err error
|
||||
|
||||
const (
|
||||
nNotaries = 2
|
||||
nKeys = 4
|
||||
)
|
||||
|
||||
// set Notary nodes and check their balance
|
||||
notaryNodes := make([]*keys.PrivateKey, nNotaries)
|
||||
notaryNodesPublicKeys := make(keys.PublicKeys, nNotaries)
|
||||
for i := range notaryNodes {
|
||||
notaryNodes[i], err = keys.NewPrivateKey()
|
||||
require.NoError(t, err)
|
||||
notaryNodesPublicKeys[i] = notaryNodes[i].PublicKey()
|
||||
}
|
||||
chain.setNodesByRole(t, true, noderoles.P2PNotary, notaryNodesPublicKeys)
|
||||
for _, notaryNode := range notaryNodesPublicKeys {
|
||||
checkBalanceOf(t, chain, notaryNode.GetScriptHash(), 0)
|
||||
}
|
||||
// deposit GAS for `signer` with lock until the next block
|
||||
depositAmount := 100_0000 + (2+int64(nKeys))*transaction.NotaryServiceFeePerKey // sysfee + netfee of the next transaction
|
||||
transferTx := transferTokenFromMultisigAccount(t, chain, notaryHash, gasHash, depositAmount, signer, int64(chain.BlockHeight()+1))
|
||||
res, err := chain.GetAppExecResults(transferTx.Hash(), trigger.Application)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, vm.HaltState, res[0].VMState)
|
||||
require.Equal(t, 0, len(res[0].Stack))
|
||||
|
||||
// save initial validators balance
|
||||
balances := make(map[int]int64, testchain.ValidatorsCount)
|
||||
for i := 0; i < testchain.ValidatorsCount; i++ {
|
||||
balances[i] = chain.GetUtilityTokenBalance(testchain.PrivateKeyByID(i).GetScriptHash()).Int64()
|
||||
}
|
||||
ic := interop.NewContext(trigger.Application, chain, chain.dao, nil, nil, nil, nil, chain.log)
|
||||
tsInitial := chain.contracts.GAS.TotalSupply(ic, nil).Value().(*big.Int).Int64()
|
||||
|
||||
// send transaction with Notary contract as a sender
|
||||
tx := chain.newTestTx(util.Uint160{}, []byte{byte(opcode.PUSH1)})
|
||||
tx.Attributes = append(tx.Attributes, transaction.Attribute{Type: transaction.NotaryAssistedT, Value: &transaction.NotaryAssisted{NKeys: uint8(nKeys)}})
|
||||
tx.NetworkFee = (2 + int64(nKeys)) * transaction.NotaryServiceFeePerKey
|
||||
tx.Signers = []transaction.Signer{
|
||||
{
|
||||
Account: notaryHash,
|
||||
Scopes: transaction.None,
|
||||
},
|
||||
{
|
||||
Account: signer,
|
||||
Scopes: transaction.None,
|
||||
},
|
||||
}
|
||||
tx.Scripts = []transaction.Witness{
|
||||
{
|
||||
InvocationScript: append([]byte{byte(opcode.PUSHDATA1), 64}, notaryNodes[0].SignHashable(uint32(testchain.Network()), tx)...),
|
||||
},
|
||||
{
|
||||
InvocationScript: testchain.Sign(tx),
|
||||
VerificationScript: testchain.MultisigVerificationScript(),
|
||||
},
|
||||
}
|
||||
b := chain.newBlock(tx)
|
||||
require.NoError(t, chain.AddBlock(b))
|
||||
checkBalanceOf(t, chain, notaryHash, int(depositAmount-tx.SystemFee-tx.NetworkFee))
|
||||
singleReward := transaction.NotaryServiceFeePerKey * (nKeys + 1) / nNotaries
|
||||
for _, notaryNode := range notaryNodesPublicKeys {
|
||||
checkBalanceOf(t, chain, notaryNode.GetScriptHash(), singleReward)
|
||||
}
|
||||
for i := 0; i < testchain.ValidatorsCount; i++ {
|
||||
newBalance := chain.GetUtilityTokenBalance(testchain.PrivateKeyByID(i).GetScriptHash()).Int64()
|
||||
expectedBalance := balances[i]
|
||||
if i == int(b.Index)%testchain.CommitteeSize() {
|
||||
// committee reward
|
||||
expectedBalance += 5000_0000
|
||||
}
|
||||
if testchain.IDToOrder(i) == int(b.PrimaryIndex) {
|
||||
// primary reward
|
||||
expectedBalance += tx.NetworkFee - int64(singleReward*nNotaries)
|
||||
}
|
||||
assert.Equal(t, expectedBalance, newBalance, i)
|
||||
}
|
||||
tsUpdated := chain.contracts.GAS.TotalSupply(ic, nil).Value().(*big.Int).Int64()
|
||||
tsExpected := tsInitial + 5000_0000 - tx.SystemFee
|
||||
require.Equal(t, tsExpected, tsUpdated)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue