forked from TrueCloudLab/neoneo-go
Merge pull request #2287 from nspcc-dev/optimizations-partN
Optimizations part N
This commit is contained in:
commit
d62f5b8c3c
19 changed files with 158 additions and 137 deletions
1
go.mod
1
go.mod
|
@ -6,6 +6,7 @@ require (
|
||||||
github.com/btcsuite/btcd v0.22.0-beta
|
github.com/btcsuite/btcd v0.22.0-beta
|
||||||
github.com/gorilla/websocket v1.4.2
|
github.com/gorilla/websocket v1.4.2
|
||||||
github.com/hashicorp/golang-lru v0.5.4
|
github.com/hashicorp/golang-lru v0.5.4
|
||||||
|
github.com/holiman/uint256 v1.2.0
|
||||||
github.com/mr-tron/base58 v1.2.0
|
github.com/mr-tron/base58 v1.2.0
|
||||||
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac
|
github.com/nspcc-dev/dbft v0.0.0-20210721160347-1b03241391ac
|
||||||
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02
|
github.com/nspcc-dev/go-ordered-json v0.0.0-20210915112629-e1b6cce73d02
|
||||||
|
|
2
go.sum
2
go.sum
|
@ -128,6 +128,8 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
|
||||||
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
|
github.com/holiman/uint256 v1.2.0 h1:gpSYcPLWGv4sG43I2mVLiDZCNDh/EpGjSk8tmtxitHM=
|
||||||
|
github.com/holiman/uint256 v1.2.0/go.mod h1:y4ga/t+u+Xwd7CpDgZESaRcWy0I7XMlTMA25ApIH5Jw=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
|
|
|
@ -3,11 +3,11 @@ package mempool
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
"github.com/nspcc-dev/neo-go/pkg/core/mempoolevent"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
@ -50,8 +50,8 @@ type items []item
|
||||||
// utilityBalanceAndFees stores sender's balance and overall fees of
|
// utilityBalanceAndFees stores sender's balance and overall fees of
|
||||||
// sender's transactions which are currently in mempool.
|
// sender's transactions which are currently in mempool.
|
||||||
type utilityBalanceAndFees struct {
|
type utilityBalanceAndFees struct {
|
||||||
balance *big.Int
|
balance uint256.Int
|
||||||
feeSum *big.Int
|
feeSum uint256.Int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pool stores the unconfirms transactions.
|
// Pool stores the unconfirms transactions.
|
||||||
|
@ -164,8 +164,7 @@ func (mp *Pool) tryAddSendersFee(tx *transaction.Transaction, feer Feer, needChe
|
||||||
payer := tx.Signers[mp.payerIndex].Account
|
payer := tx.Signers[mp.payerIndex].Account
|
||||||
senderFee, ok := mp.fees[payer]
|
senderFee, ok := mp.fees[payer]
|
||||||
if !ok {
|
if !ok {
|
||||||
senderFee.balance = feer.GetUtilityTokenBalance(payer)
|
_ = senderFee.balance.SetFromBig(feer.GetUtilityTokenBalance(payer))
|
||||||
senderFee.feeSum = big.NewInt(0)
|
|
||||||
mp.fees[payer] = senderFee
|
mp.fees[payer] = senderFee
|
||||||
}
|
}
|
||||||
if needCheck {
|
if needCheck {
|
||||||
|
@ -173,23 +172,26 @@ func (mp *Pool) tryAddSendersFee(tx *transaction.Transaction, feer Feer, needChe
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
senderFee.feeSum.Set(newFeeSum)
|
senderFee.feeSum = newFeeSum
|
||||||
} else {
|
} else {
|
||||||
senderFee.feeSum.Add(senderFee.feeSum, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
senderFee.feeSum.AddUint64(&senderFee.feeSum, uint64(tx.SystemFee+tx.NetworkFee))
|
||||||
}
|
}
|
||||||
|
mp.fees[payer] = senderFee
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkBalance returns new cumulative fee balance for account or an error in
|
// checkBalance returns new cumulative fee balance for account or an error in
|
||||||
// case sender doesn't have enough GAS to pay for the transaction.
|
// case sender doesn't have enough GAS to pay for the transaction.
|
||||||
func checkBalance(tx *transaction.Transaction, balance utilityBalanceAndFees) (*big.Int, error) {
|
func checkBalance(tx *transaction.Transaction, balance utilityBalanceAndFees) (uint256.Int, error) {
|
||||||
txFee := big.NewInt(tx.SystemFee + tx.NetworkFee)
|
var txFee uint256.Int
|
||||||
if balance.balance.Cmp(txFee) < 0 {
|
|
||||||
return nil, ErrInsufficientFunds
|
txFee.SetUint64(uint64(tx.SystemFee + tx.NetworkFee))
|
||||||
|
if balance.balance.Cmp(&txFee) < 0 {
|
||||||
|
return txFee, ErrInsufficientFunds
|
||||||
}
|
}
|
||||||
txFee.Add(txFee, balance.feeSum)
|
txFee.Add(&txFee, &balance.feeSum)
|
||||||
if balance.balance.Cmp(txFee) < 0 {
|
if balance.balance.Cmp(&txFee) < 0 {
|
||||||
return nil, ErrConflict
|
return txFee, ErrConflict
|
||||||
}
|
}
|
||||||
return txFee, nil
|
return txFee, nil
|
||||||
}
|
}
|
||||||
|
@ -323,7 +325,7 @@ func (mp *Pool) removeInternal(hash util.Uint256, feer Feer) {
|
||||||
}
|
}
|
||||||
payer := itm.txn.Signers[mp.payerIndex].Account
|
payer := itm.txn.Signers[mp.payerIndex].Account
|
||||||
senderFee := mp.fees[payer]
|
senderFee := mp.fees[payer]
|
||||||
senderFee.feeSum.Sub(senderFee.feeSum, big.NewInt(tx.SystemFee+tx.NetworkFee))
|
senderFee.feeSum.SubUint64(&senderFee.feeSum, uint64(tx.SystemFee+tx.NetworkFee))
|
||||||
mp.fees[payer] = senderFee
|
mp.fees[payer] = senderFee
|
||||||
if feer.P2PSigExtensionsEnabled() {
|
if feer.P2PSigExtensionsEnabled() {
|
||||||
// remove all conflicting hashes from mp.conflicts list
|
// remove all conflicting hashes from mp.conflicts list
|
||||||
|
@ -420,7 +422,7 @@ func (mp *Pool) checkPolicy(tx *transaction.Transaction, policyChanged bool) boo
|
||||||
// New returns a new Pool struct.
|
// New returns a new Pool struct.
|
||||||
func New(capacity int, payerIndex int, enableSubscriptions bool) *Pool {
|
func New(capacity int, payerIndex int, enableSubscriptions bool) *Pool {
|
||||||
mp := &Pool{
|
mp := &Pool{
|
||||||
verifiedMap: make(map[util.Uint256]*transaction.Transaction),
|
verifiedMap: make(map[util.Uint256]*transaction.Transaction, capacity),
|
||||||
verifiedTxes: make([]item, 0, capacity),
|
verifiedTxes: make([]item, 0, capacity),
|
||||||
capacity: capacity,
|
capacity: capacity,
|
||||||
payerIndex: payerIndex,
|
payerIndex: payerIndex,
|
||||||
|
@ -507,8 +509,7 @@ func (mp *Pool) checkTxConflicts(tx *transaction.Transaction, fee Feer) ([]*tran
|
||||||
payer := tx.Signers[mp.payerIndex].Account
|
payer := tx.Signers[mp.payerIndex].Account
|
||||||
actualSenderFee, ok := mp.fees[payer]
|
actualSenderFee, ok := mp.fees[payer]
|
||||||
if !ok {
|
if !ok {
|
||||||
actualSenderFee.balance = fee.GetUtilityTokenBalance(payer)
|
actualSenderFee.balance.SetFromBig(fee.GetUtilityTokenBalance(payer))
|
||||||
actualSenderFee.feeSum = big.NewInt(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedSenderFee utilityBalanceAndFees
|
var expectedSenderFee utilityBalanceAndFees
|
||||||
|
@ -541,13 +542,10 @@ func (mp *Pool) checkTxConflicts(tx *transaction.Transaction, fee Feer) ([]*tran
|
||||||
conflictsToBeRemoved = append(conflictsToBeRemoved, existingTx)
|
conflictsToBeRemoved = append(conflictsToBeRemoved, existingTx)
|
||||||
}
|
}
|
||||||
// Step 3: take into account sender's conflicting transactions before balance check.
|
// Step 3: take into account sender's conflicting transactions before balance check.
|
||||||
expectedSenderFee = utilityBalanceAndFees{
|
expectedSenderFee = actualSenderFee
|
||||||
balance: new(big.Int).Set(actualSenderFee.balance),
|
|
||||||
feeSum: new(big.Int).Set(actualSenderFee.feeSum),
|
|
||||||
}
|
|
||||||
for _, conflictingTx := range conflictsToBeRemoved {
|
for _, conflictingTx := range conflictsToBeRemoved {
|
||||||
if conflictingTx.Signers[mp.payerIndex].Account.Equals(payer) {
|
if conflictingTx.Signers[mp.payerIndex].Account.Equals(payer) {
|
||||||
expectedSenderFee.feeSum.Sub(expectedSenderFee.feeSum, big.NewInt(conflictingTx.SystemFee+conflictingTx.NetworkFee))
|
expectedSenderFee.feeSum.SubUint64(&expectedSenderFee.feeSum, uint64(conflictingTx.SystemFee+conflictingTx.NetworkFee))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/holiman/uint256"
|
||||||
"github.com/nspcc-dev/neo-go/internal/random"
|
"github.com/nspcc-dev/neo-go/internal/random"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
"github.com/nspcc-dev/neo-go/pkg/network/payload"
|
||||||
|
@ -268,8 +269,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.NoError(t, mp.Add(tx1, fs))
|
require.NoError(t, mp.Add(tx1, fs))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(tx1.NetworkFee),
|
feeSum: *uint256.NewInt(uint64(tx1.NetworkFee)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// balance shouldn't change after adding one more transaction
|
// balance shouldn't change after adding one more transaction
|
||||||
|
@ -280,8 +281,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.Equal(t, 2, len(mp.verifiedTxes))
|
require.Equal(t, 2, len(mp.verifiedTxes))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(fs.balance),
|
feeSum: *uint256.NewInt(uint64(fs.balance)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// can't add more transactions as we don't have enough GAS
|
// can't add more transactions as we don't have enough GAS
|
||||||
|
@ -292,8 +293,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
require.Error(t, mp.Add(tx3, fs))
|
require.Error(t, mp.Add(tx3, fs))
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(fs.balance),
|
feeSum: *uint256.NewInt(uint64(fs.balance)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// check whether sender's fee updates correctly
|
// check whether sender's fee updates correctly
|
||||||
|
@ -302,8 +303,8 @@ func TestMemPoolFees(t *testing.T) {
|
||||||
}, fs)
|
}, fs)
|
||||||
require.Equal(t, 1, len(mp.fees))
|
require.Equal(t, 1, len(mp.fees))
|
||||||
require.Equal(t, utilityBalanceAndFees{
|
require.Equal(t, utilityBalanceAndFees{
|
||||||
balance: big.NewInt(fs.balance),
|
balance: *uint256.NewInt(uint64(fs.balance)),
|
||||||
feeSum: big.NewInt(tx2.NetworkFee),
|
feeSum: *uint256.NewInt(uint64(tx2.NetworkFee)),
|
||||||
}, mp.fees[sender0])
|
}, mp.fees[sender0])
|
||||||
|
|
||||||
// there should be nothing left
|
// there should be nothing left
|
||||||
|
|
|
@ -90,6 +90,12 @@ const (
|
||||||
var (
|
var (
|
||||||
// prefixCommittee is a key used to store committee.
|
// prefixCommittee is a key used to store committee.
|
||||||
prefixCommittee = []byte{14}
|
prefixCommittee = []byte{14}
|
||||||
|
|
||||||
|
bigCommitteeRewardRatio = big.NewInt(committeeRewardRatio)
|
||||||
|
bigVoterRewardRatio = big.NewInt(voterRewardRatio)
|
||||||
|
bigVoterRewardFactor = big.NewInt(voterRewardFactor)
|
||||||
|
bigEffectiveVoterTurnout = big.NewInt(effectiveVoterTurnout)
|
||||||
|
big100 = big.NewInt(100)
|
||||||
)
|
)
|
||||||
|
|
||||||
// makeValidatorKey creates a key from account script hash.
|
// makeValidatorKey creates a key from account script hash.
|
||||||
|
@ -316,24 +322,26 @@ func (n *NEO) PostPersist(ic *interop.Context) error {
|
||||||
pubs := n.GetCommitteeMembers()
|
pubs := n.GetCommitteeMembers()
|
||||||
committeeSize := len(ic.Chain.GetConfig().StandbyCommittee)
|
committeeSize := len(ic.Chain.GetConfig().StandbyCommittee)
|
||||||
index := int(ic.Block.Index) % committeeSize
|
index := int(ic.Block.Index) % committeeSize
|
||||||
committeeReward := new(big.Int).Mul(gas, big.NewInt(committeeRewardRatio))
|
committeeReward := new(big.Int).Mul(gas, bigCommitteeRewardRatio)
|
||||||
n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big.NewInt(100)), false)
|
n.GAS.mint(ic, pubs[index].GetScriptHash(), committeeReward.Div(committeeReward, big100), false)
|
||||||
|
|
||||||
if ShouldUpdateCommittee(ic.Block.Index, ic.Chain) {
|
if ShouldUpdateCommittee(ic.Block.Index, ic.Chain) {
|
||||||
var voterReward = big.NewInt(voterRewardRatio)
|
var voterReward = new(big.Int).Set(bigVoterRewardRatio)
|
||||||
voterReward.Mul(voterReward, gas)
|
voterReward.Mul(voterReward, gas)
|
||||||
voterReward.Mul(voterReward, big.NewInt(voterRewardFactor*int64(committeeSize)))
|
voterReward.Mul(voterReward, big.NewInt(voterRewardFactor*int64(committeeSize)))
|
||||||
var validatorsCount = ic.Chain.GetConfig().ValidatorsCount
|
var validatorsCount = ic.Chain.GetConfig().ValidatorsCount
|
||||||
voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
|
voterReward.Div(voterReward, big.NewInt(int64(committeeSize+validatorsCount)))
|
||||||
voterReward.Div(voterReward, big.NewInt(100))
|
voterReward.Div(voterReward, big100)
|
||||||
|
|
||||||
var cs = n.committee.Load().(keysWithVotes)
|
var cs = n.committee.Load().(keysWithVotes)
|
||||||
var key = make([]byte, 38)
|
var key = make([]byte, 38)
|
||||||
for i := range cs {
|
for i := range cs {
|
||||||
if cs[i].Votes.Sign() > 0 {
|
if cs[i].Votes.Sign() > 0 {
|
||||||
tmp := big.NewInt(1)
|
var tmp = new(big.Int)
|
||||||
if i < validatorsCount {
|
if i < validatorsCount {
|
||||||
tmp = big.NewInt(2)
|
tmp.Set(intTwo)
|
||||||
|
} else {
|
||||||
|
tmp.Set(intOne)
|
||||||
}
|
}
|
||||||
tmp.Mul(tmp, voterReward)
|
tmp.Mul(tmp, voterReward)
|
||||||
tmp.Div(tmp, cs[i].Votes)
|
tmp.Div(tmp, cs[i].Votes)
|
||||||
|
@ -633,7 +641,7 @@ func (n *NEO) calculateBonus(d dao.DAO, vote *keys.PublicKey, value *big.Int, st
|
||||||
var reward = n.getGASPerVote(d, key, start, end)
|
var reward = n.getGASPerVote(d, key, start, end)
|
||||||
var tmp = new(big.Int).Sub(&reward[1], &reward[0])
|
var tmp = new(big.Int).Sub(&reward[1], &reward[0])
|
||||||
tmp.Mul(tmp, value)
|
tmp.Mul(tmp, value)
|
||||||
tmp.Div(tmp, big.NewInt(voterRewardFactor))
|
tmp.Div(tmp, bigVoterRewardFactor)
|
||||||
tmp.Add(tmp, r)
|
tmp.Add(tmp, r)
|
||||||
return tmp, nil
|
return tmp, nil
|
||||||
}
|
}
|
||||||
|
@ -982,7 +990,7 @@ func (n *NEO) computeCommitteeMembers(bc blockchainer.Blockchainer, d dao.DAO) (
|
||||||
}
|
}
|
||||||
votersCount := bigint.FromBytes(si)
|
votersCount := bigint.FromBytes(si)
|
||||||
// votersCount / totalSupply must be >= 0.2
|
// votersCount / totalSupply must be >= 0.2
|
||||||
votersCount.Mul(votersCount, big.NewInt(effectiveVoterTurnout))
|
votersCount.Mul(votersCount, bigEffectiveVoterTurnout)
|
||||||
_, totalSupply := n.getTotalSupply(d)
|
_, totalSupply := n.getTotalSupply(d)
|
||||||
voterTurnout := votersCount.Div(votersCount, totalSupply)
|
voterTurnout := votersCount.Div(votersCount, totalSupply)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var intOne = big.NewInt(1)
|
var intOne = big.NewInt(1)
|
||||||
|
var intTwo = big.NewInt(2)
|
||||||
|
|
||||||
func getConvertibleFromDAO(id int32, d dao.DAO, key []byte, conv stackitem.Convertible) error {
|
func getConvertibleFromDAO(id int32, d dao.DAO, key []byte, conv stackitem.Convertible) error {
|
||||||
si := d.GetStorageItem(id, key)
|
si := d.GetStorageItem(id, key)
|
||||||
|
|
|
@ -252,8 +252,8 @@ func (s *MemCachedStore) persist(isSync bool) (int, error) {
|
||||||
// unprotected while writes are handled by s proper.
|
// unprotected while writes are handled by s proper.
|
||||||
var tempstore = &MemCachedStore{MemoryStore: MemoryStore{mem: s.mem, del: s.del}, ps: s.ps}
|
var tempstore = &MemCachedStore{MemoryStore: MemoryStore{mem: s.mem, del: s.del}, ps: s.ps}
|
||||||
s.ps = tempstore
|
s.ps = tempstore
|
||||||
s.mem = make(map[string][]byte)
|
s.mem = make(map[string][]byte, len(s.mem))
|
||||||
s.del = make(map[string]bool)
|
s.del = make(map[string]bool, len(s.del))
|
||||||
if !isSync {
|
if !isSync {
|
||||||
s.mut.Unlock()
|
s.mut.Unlock()
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,9 @@ const SignatureLen = 64
|
||||||
// PublicKeys is a list of public keys.
|
// PublicKeys is a list of public keys.
|
||||||
type PublicKeys []*PublicKey
|
type PublicKeys []*PublicKey
|
||||||
|
|
||||||
|
var big0 = big.NewInt(0)
|
||||||
|
var big3 = big.NewInt(3)
|
||||||
|
|
||||||
func (keys PublicKeys) Len() int { return len(keys) }
|
func (keys PublicKeys) Len() int { return len(keys) }
|
||||||
func (keys PublicKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] }
|
func (keys PublicKeys) Swap(i, j int) { keys[i], keys[j] = keys[j], keys[i] }
|
||||||
func (keys PublicKeys) Less(i, j int) bool {
|
func (keys PublicKeys) Less(i, j int) bool {
|
||||||
|
@ -189,12 +192,12 @@ func decodeCompressedY(x *big.Int, ylsb uint, curve elliptic.Curve) (*big.Int, e
|
||||||
var a *big.Int
|
var a *big.Int
|
||||||
switch curve.(type) {
|
switch curve.(type) {
|
||||||
case *btcec.KoblitzCurve:
|
case *btcec.KoblitzCurve:
|
||||||
a = big.NewInt(0)
|
a = big0
|
||||||
default:
|
default:
|
||||||
a = big.NewInt(3)
|
a = big3
|
||||||
}
|
}
|
||||||
cp := curve.Params()
|
cp := curve.Params()
|
||||||
xCubed := new(big.Int).Exp(x, big.NewInt(3), cp.P)
|
xCubed := new(big.Int).Exp(x, big3, cp.P)
|
||||||
aX := new(big.Int).Mul(x, a)
|
aX := new(big.Int).Mul(x, a)
|
||||||
aX.Mod(aX, cp.P)
|
aX.Mod(aX, cp.P)
|
||||||
ySquared := new(big.Int).Sub(xCubed, aX)
|
ySquared := new(big.Int).Sub(xCubed, aX)
|
||||||
|
|
|
@ -15,6 +15,8 @@ const (
|
||||||
wordSizeBytes = bits.UintSize / 8
|
wordSizeBytes = bits.UintSize / 8
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var bigOne = big.NewInt(1)
|
||||||
|
|
||||||
// FromBytesUnsigned converts data in little-endian format to an unsigned integer.
|
// FromBytesUnsigned converts data in little-endian format to an unsigned integer.
|
||||||
func FromBytesUnsigned(data []byte) *big.Int {
|
func FromBytesUnsigned(data []byte) *big.Int {
|
||||||
bs := slice.CopyReverse(data)
|
bs := slice.CopyReverse(data)
|
||||||
|
@ -70,7 +72,7 @@ func FromBytes(data []byte) *big.Int {
|
||||||
n.SetBits(ws)
|
n.SetBits(ws)
|
||||||
n.Neg(n)
|
n.Neg(n)
|
||||||
|
|
||||||
return n.Sub(n, big.NewInt(1))
|
return n.Sub(n, bigOne)
|
||||||
}
|
}
|
||||||
|
|
||||||
return n.SetBits(ws)
|
return n.SetBits(ws)
|
||||||
|
@ -114,7 +116,7 @@ func ToPreallocatedBytes(n *big.Int, data []byte) []byte {
|
||||||
if sign == 1 {
|
if sign == 1 {
|
||||||
ws = n.Bits()
|
ws = n.Bits()
|
||||||
} else {
|
} else {
|
||||||
n1 := new(big.Int).Add(n, big.NewInt(1))
|
n1 := new(big.Int).Add(n, bigOne)
|
||||||
if n1.Sign() == 0 { // n == -1
|
if n1.Sign() == 0 { // n == -1
|
||||||
return append(data, 0xFF)
|
return append(data, 0xFF)
|
||||||
}
|
}
|
||||||
|
|
|
@ -143,7 +143,11 @@ func (w *BinWriter) WriteVarBytes(b []byte) {
|
||||||
|
|
||||||
// WriteString writes a variable length string into the underlying io.Writer.
|
// WriteString writes a variable length string into the underlying io.Writer.
|
||||||
func (w *BinWriter) WriteString(s string) {
|
func (w *BinWriter) WriteString(s string) {
|
||||||
w.WriteVarBytes([]byte(s))
|
w.WriteVarUint(uint64(len(s)))
|
||||||
|
if w.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, w.Err = io.WriteString(w.w, s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grow tries to increase underlying buffer capacity so that at least n bytes
|
// Grow tries to increase underlying buffer capacity so that at least n bytes
|
||||||
|
|
|
@ -32,9 +32,9 @@ type Context struct {
|
||||||
// Evaluation stack pointer.
|
// Evaluation stack pointer.
|
||||||
estack *Stack
|
estack *Stack
|
||||||
|
|
||||||
static *Slot
|
static *slot
|
||||||
local *Slot
|
local slot
|
||||||
arguments *Slot
|
arguments slot
|
||||||
|
|
||||||
// Exception context stack.
|
// Exception context stack.
|
||||||
tryStack Stack
|
tryStack Stack
|
||||||
|
@ -277,16 +277,19 @@ func (c *Context) DumpStaticSlot() string {
|
||||||
|
|
||||||
// DumpLocalSlot returns json formatted representation of the given slot.
|
// DumpLocalSlot returns json formatted representation of the given slot.
|
||||||
func (c *Context) DumpLocalSlot() string {
|
func (c *Context) DumpLocalSlot() string {
|
||||||
return dumpSlot(c.local)
|
return dumpSlot(&c.local)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpArgumentsSlot returns json formatted representation of the given slot.
|
// DumpArgumentsSlot returns json formatted representation of the given slot.
|
||||||
func (c *Context) DumpArgumentsSlot() string {
|
func (c *Context) DumpArgumentsSlot() string {
|
||||||
return dumpSlot(c.arguments)
|
return dumpSlot(&c.arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
// dumpSlot returns json formatted representation of the given slot.
|
// dumpSlot returns json formatted representation of the given slot.
|
||||||
func dumpSlot(s *Slot) string {
|
func dumpSlot(s *slot) string {
|
||||||
|
if s == nil || *s == nil {
|
||||||
|
return "[]"
|
||||||
|
}
|
||||||
b, _ := json.MarshalIndent(s, "", " ")
|
b, _ := json.MarshalIndent(s, "", " ")
|
||||||
return string(b)
|
return string(b)
|
||||||
}
|
}
|
||||||
|
|
|
@ -239,8 +239,8 @@ func compareStacks(t *testing.T, expected []vmUTStackItem, actual *Stack) {
|
||||||
compareItemArrays(t, expected, actual.Len(), func(i int) stackitem.Item { return actual.Peek(i).Item() })
|
compareItemArrays(t, expected, actual.Len(), func(i int) stackitem.Item { return actual.Peek(i).Item() })
|
||||||
}
|
}
|
||||||
|
|
||||||
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *Slot) {
|
func compareSlots(t *testing.T, expected []vmUTStackItem, actual *slot) {
|
||||||
if actual.storage == nil && len(expected) == 0 {
|
if (actual == nil || *actual == nil) && len(expected) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
require.NotNil(t, actual)
|
require.NotNil(t, actual)
|
||||||
|
|
|
@ -59,8 +59,8 @@ func opParamSlotsPushVM(op opcode.Opcode, param []byte, sslot int, slotloc int,
|
||||||
v.Context().static.init(sslot)
|
v.Context().static.init(sslot)
|
||||||
}
|
}
|
||||||
if slotloc != 0 && slotarg != 0 {
|
if slotloc != 0 && slotarg != 0 {
|
||||||
v.Context().local = v.newSlot(slotloc)
|
v.Context().local.init(slotloc)
|
||||||
v.Context().arguments = v.newSlot(slotarg)
|
v.Context().arguments.init(slotarg)
|
||||||
}
|
}
|
||||||
for i := range items {
|
for i := range items {
|
||||||
item, ok := items[i].(stackitem.Item)
|
item, ok := items[i].(stackitem.Item)
|
||||||
|
|
|
@ -6,75 +6,58 @@ import (
|
||||||
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Slot is a fixed-size slice of stack items.
|
// slot is a fixed-size slice of stack items.
|
||||||
type Slot struct {
|
type slot []stackitem.Item
|
||||||
storage []stackitem.Item
|
|
||||||
refs *refCounter
|
|
||||||
}
|
|
||||||
|
|
||||||
// newSlot returns new slot with the provided reference counter.
|
|
||||||
func newSlot(refs *refCounter) *Slot {
|
|
||||||
return &Slot{
|
|
||||||
refs: refs,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
// init sets static slot size to n. It is intended to be used only by INITSSLOT.
|
||||||
func (s *Slot) init(n int) {
|
func (s *slot) init(n int) {
|
||||||
if s.storage != nil {
|
if *s != nil {
|
||||||
panic("already initialized")
|
panic("already initialized")
|
||||||
}
|
}
|
||||||
s.storage = make([]stackitem.Item, n)
|
*s = make([]stackitem.Item, n)
|
||||||
}
|
|
||||||
|
|
||||||
func (v *VM) newSlot(n int) *Slot {
|
|
||||||
s := newSlot(&v.refs)
|
|
||||||
s.init(n)
|
|
||||||
return s
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set sets i-th storage slot.
|
// Set sets i-th storage slot.
|
||||||
func (s *Slot) Set(i int, item stackitem.Item) {
|
func (s slot) Set(i int, item stackitem.Item, refs *refCounter) {
|
||||||
if s.storage[i] == item {
|
if s[i] == item {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
old := s.storage[i]
|
old := s[i]
|
||||||
s.storage[i] = item
|
s[i] = item
|
||||||
if old != nil {
|
if old != nil {
|
||||||
s.refs.Remove(old)
|
refs.Remove(old)
|
||||||
}
|
}
|
||||||
s.refs.Add(item)
|
refs.Add(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns item contained in i-th slot.
|
// Get returns item contained in i-th slot.
|
||||||
func (s *Slot) Get(i int) stackitem.Item {
|
func (s slot) Get(i int) stackitem.Item {
|
||||||
if item := s.storage[i]; item != nil {
|
if item := s[i]; item != nil {
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
return stackitem.Null{}
|
return stackitem.Null{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear removes all slot variables from reference counter.
|
// Clear removes all slot variables from reference counter.
|
||||||
func (s *Slot) Clear() {
|
func (s slot) Clear(refs *refCounter) {
|
||||||
for _, item := range s.storage {
|
for _, item := range s {
|
||||||
s.refs.Remove(item)
|
refs.Remove(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Size returns slot size.
|
// Size returns slot size.
|
||||||
func (s *Slot) Size() int {
|
func (s slot) Size() int {
|
||||||
if s.storage == nil {
|
if s == nil {
|
||||||
panic("not initialized")
|
panic("not initialized")
|
||||||
}
|
}
|
||||||
return len(s.storage)
|
return len(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON implements JSON marshalling interface.
|
// MarshalJSON implements JSON marshalling interface.
|
||||||
func (s *Slot) MarshalJSON() ([]byte, error) {
|
func (s slot) MarshalJSON() ([]byte, error) {
|
||||||
items := s.storage
|
arr := make([]json.RawMessage, len(s))
|
||||||
arr := make([]json.RawMessage, len(items))
|
for i := range s {
|
||||||
for i := range items {
|
data, err := stackitem.ToJSONWithTypes(s[i])
|
||||||
data, err := stackitem.ToJSONWithTypes(items[i])
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
arr[i] = data
|
arr[i] = data
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSlot_Get(t *testing.T) {
|
func TestSlot_Get(t *testing.T) {
|
||||||
s := newSlot(newRefCounter())
|
rc := newRefCounter()
|
||||||
require.NotNil(t, s)
|
var s slot
|
||||||
require.Panics(t, func() { s.Size() })
|
require.Panics(t, func() { s.Size() })
|
||||||
|
|
||||||
s.init(3)
|
s.init(3)
|
||||||
|
@ -20,6 +20,6 @@ func TestSlot_Get(t *testing.T) {
|
||||||
item := s.Get(2)
|
item := s.Get(2)
|
||||||
require.Equal(t, stackitem.Null{}, item)
|
require.Equal(t, stackitem.Null{}, item)
|
||||||
|
|
||||||
s.Set(1, stackitem.NewBigInteger(big.NewInt(42)))
|
s.Set(1, stackitem.NewBigInteger(big.NewInt(42)), rc)
|
||||||
require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1))
|
require.Equal(t, stackitem.NewBigInteger(big.NewInt(42)), s.Get(1))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1097,7 +1097,7 @@ func (i *Buffer) Len() int {
|
||||||
// Values of Interop items are not deeply copied.
|
// Values of Interop items are not deeply copied.
|
||||||
// It does preserve duplicates only for non-primitive types.
|
// It does preserve duplicates only for non-primitive types.
|
||||||
func DeepCopy(item Item) Item {
|
func DeepCopy(item Item) Item {
|
||||||
seen := make(map[Item]Item)
|
seen := make(map[Item]Item, typicalNumOfItems)
|
||||||
return deepCopy(item, seen)
|
return deepCopy(item, seen)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ var ErrTooDeep = errors.New("too deep")
|
||||||
// Array, Struct -> array
|
// Array, Struct -> array
|
||||||
// Map -> map with keys as UTF-8 bytes
|
// Map -> map with keys as UTF-8 bytes
|
||||||
func ToJSON(item Item) ([]byte, error) {
|
func ToJSON(item Item) ([]byte, error) {
|
||||||
seen := make(map[Item]sliceNoPointer)
|
seen := make(map[Item]sliceNoPointer, typicalNumOfItems)
|
||||||
return toJSON(nil, seen, item)
|
return toJSON(nil, seen, item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,7 +260,7 @@ func (d *decoder) decodeMap() (*Map, error) {
|
||||||
|
|
||||||
// ToJSONWithTypes serializes any stackitem to JSON in a lossless way.
|
// ToJSONWithTypes serializes any stackitem to JSON in a lossless way.
|
||||||
func ToJSONWithTypes(item Item) ([]byte, error) {
|
func ToJSONWithTypes(item Item) ([]byte, error) {
|
||||||
result, err := toJSONWithTypes(item, make(map[Item]bool))
|
result, err := toJSONWithTypes(item, make(map[Item]bool, typicalNumOfItems))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,12 @@ import (
|
||||||
// (including itself).
|
// (including itself).
|
||||||
const MaxDeserialized = 2048
|
const MaxDeserialized = 2048
|
||||||
|
|
||||||
|
// typicalNumOfItems is the number of items covering most serializaton needs.
|
||||||
|
// It's a hint used for map creation, so it's not limiting anything, it's just
|
||||||
|
// a microoptimization to avoid excessive reallocations. Most of the serialized
|
||||||
|
// items are structs, so there is at least one of them.
|
||||||
|
const typicalNumOfItems = 4
|
||||||
|
|
||||||
// ErrRecursive is returned on attempts to serialize some recursive stack item
|
// ErrRecursive is returned on attempts to serialize some recursive stack item
|
||||||
// (like array including an item with reference to the same array).
|
// (like array including an item with reference to the same array).
|
||||||
var ErrRecursive = errors.New("recursive item")
|
var ErrRecursive = errors.New("recursive item")
|
||||||
|
@ -40,7 +46,7 @@ type deserContext struct {
|
||||||
func Serialize(item Item) ([]byte, error) {
|
func Serialize(item Item) ([]byte, error) {
|
||||||
sc := serContext{
|
sc := serContext{
|
||||||
allowInvalid: false,
|
allowInvalid: false,
|
||||||
seen: make(map[Item]sliceNoPointer),
|
seen: make(map[Item]sliceNoPointer, typicalNumOfItems),
|
||||||
}
|
}
|
||||||
err := sc.serialize(item)
|
err := sc.serialize(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,7 +75,7 @@ func EncodeBinary(item Item, w *io.BinWriter) {
|
||||||
func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
||||||
sc := serContext{
|
sc := serContext{
|
||||||
allowInvalid: true,
|
allowInvalid: true,
|
||||||
seen: make(map[Item]sliceNoPointer),
|
seen: make(map[Item]sliceNoPointer, typicalNumOfItems),
|
||||||
}
|
}
|
||||||
err := sc.serialize(item)
|
err := sc.serialize(item)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -79,6 +85,18 @@ func EncodeBinaryProtected(item Item, w *io.BinWriter) {
|
||||||
w.WriteBytes(sc.data)
|
w.WriteBytes(sc.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w *serContext) writeArray(item Item, arr []Item, start int) error {
|
||||||
|
w.seen[item] = sliceNoPointer{}
|
||||||
|
w.appendVarUint(uint64(len(arr)))
|
||||||
|
for i := range arr {
|
||||||
|
if err := w.serialize(arr[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
w.seen[item] = sliceNoPointer{start, len(w.data)}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (w *serContext) serialize(item Item) error {
|
func (w *serContext) serialize(item Item) error {
|
||||||
if v, ok := w.seen[item]; ok {
|
if v, ok := w.seen[item]; ok {
|
||||||
if v.start == v.end {
|
if v.start == v.end {
|
||||||
|
@ -121,28 +139,20 @@ func (w *serContext) serialize(item Item) error {
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("%w: Interop", ErrUnserializable)
|
return fmt.Errorf("%w: Interop", ErrUnserializable)
|
||||||
}
|
}
|
||||||
case *Array, *Struct:
|
case *Array:
|
||||||
w.seen[item] = sliceNoPointer{}
|
|
||||||
|
|
||||||
_, isArray := t.(*Array)
|
|
||||||
if isArray {
|
|
||||||
w.data = append(w.data, byte(ArrayT))
|
w.data = append(w.data, byte(ArrayT))
|
||||||
} else {
|
if err := w.writeArray(item, t.value, start); err != nil {
|
||||||
w.data = append(w.data, byte(StructT))
|
|
||||||
}
|
|
||||||
|
|
||||||
arr := t.Value().([]Item)
|
|
||||||
w.appendVarUint(uint64(len(arr)))
|
|
||||||
for i := range arr {
|
|
||||||
if err := w.serialize(arr[i]); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
case *Struct:
|
||||||
|
w.data = append(w.data, byte(StructT))
|
||||||
|
if err := w.writeArray(item, t.value, start); err != nil {
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
w.seen[item] = sliceNoPointer{start, len(w.data)}
|
|
||||||
case *Map:
|
case *Map:
|
||||||
w.seen[item] = sliceNoPointer{}
|
w.seen[item] = sliceNoPointer{}
|
||||||
|
|
||||||
elems := t.Value().([]MapElement)
|
elems := t.value
|
||||||
w.data = append(w.data, byte(MapT))
|
w.data = append(w.data, byte(MapT))
|
||||||
w.appendVarUint(uint64(len(elems)))
|
w.appendVarUint(uint64(len(elems)))
|
||||||
for i := range elems {
|
for i := range elems {
|
||||||
|
|
35
pkg/vm/vm.go
35
pkg/vm/vm.go
|
@ -90,6 +90,8 @@ type VM struct {
|
||||||
invTree *InvocationTree
|
invTree *InvocationTree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var bigOne = big.NewInt(1)
|
||||||
|
|
||||||
// New returns a new VM object ready to load AVM bytecode scripts.
|
// New returns a new VM object ready to load AVM bytecode scripts.
|
||||||
func New() *VM {
|
func New() *VM {
|
||||||
return NewWithTrigger(trigger.Application)
|
return NewWithTrigger(trigger.Application)
|
||||||
|
@ -105,6 +107,7 @@ func NewWithTrigger(t trigger.Type) *VM {
|
||||||
}
|
}
|
||||||
|
|
||||||
initStack(&vm.istack, "invocation", nil)
|
initStack(&vm.istack, "invocation", nil)
|
||||||
|
vm.istack.elems = make([]Element, 0, 8) // Most of invocations use one-two contracts, but they're likely to have internal calls.
|
||||||
vm.estack = newStack("evaluation", &vm.refs)
|
vm.estack = newStack("evaluation", &vm.refs)
|
||||||
return vm
|
return vm
|
||||||
}
|
}
|
||||||
|
@ -310,13 +313,15 @@ func (v *VM) LoadNEFMethod(exe *nef.File, caller util.Uint160, hash util.Uint160
|
||||||
// It should be used for calling from native contracts.
|
// It should be used for calling from native contracts.
|
||||||
func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, caller util.Uint160,
|
func (v *VM) loadScriptWithCallingHash(b []byte, exe *nef.File, caller util.Uint160,
|
||||||
hash util.Uint160, f callflag.CallFlag, rvcount int, offset int) {
|
hash util.Uint160, f callflag.CallFlag, rvcount int, offset int) {
|
||||||
|
var sl slot
|
||||||
|
|
||||||
v.checkInvocationStackSize()
|
v.checkInvocationStackSize()
|
||||||
ctx := NewContextWithParams(b, rvcount, offset)
|
ctx := NewContextWithParams(b, rvcount, offset)
|
||||||
v.estack = newStack("evaluation", &v.refs)
|
v.estack = newStack("evaluation", &v.refs)
|
||||||
ctx.estack = v.estack
|
ctx.estack = v.estack
|
||||||
initStack(&ctx.tryStack, "exception", nil)
|
initStack(&ctx.tryStack, "exception", nil)
|
||||||
ctx.callFlag = f
|
ctx.callFlag = f
|
||||||
ctx.static = newSlot(&v.refs)
|
ctx.static = &sl
|
||||||
ctx.scriptHash = hash
|
ctx.scriptHash = hash
|
||||||
ctx.callingScriptHash = caller
|
ctx.callingScriptHash = caller
|
||||||
ctx.NEF = exe
|
ctx.NEF = exe
|
||||||
|
@ -615,13 +620,13 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
panic("zero argument")
|
panic("zero argument")
|
||||||
}
|
}
|
||||||
if parameter[0] > 0 {
|
if parameter[0] > 0 {
|
||||||
ctx.local = v.newSlot(int(parameter[0]))
|
ctx.local.init(int(parameter[0]))
|
||||||
}
|
}
|
||||||
if parameter[1] > 0 {
|
if parameter[1] > 0 {
|
||||||
sz := int(parameter[1])
|
sz := int(parameter[1])
|
||||||
ctx.arguments = v.newSlot(sz)
|
ctx.arguments.init(sz)
|
||||||
for i := 0; i < sz; i++ {
|
for i := 0; i < sz; i++ {
|
||||||
ctx.arguments.Set(i, v.estack.Pop().Item())
|
ctx.arguments.Set(i, v.estack.Pop().Item(), &v.refs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,11 +640,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STSFLD0, opcode.STSFLD1, opcode.STSFLD2, opcode.STSFLD3, opcode.STSFLD4, opcode.STSFLD5, opcode.STSFLD6:
|
case opcode.STSFLD0, opcode.STSFLD1, opcode.STSFLD2, opcode.STSFLD3, opcode.STSFLD4, opcode.STSFLD5, opcode.STSFLD6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.static.Set(int(op-opcode.STSFLD0), item)
|
ctx.static.Set(int(op-opcode.STSFLD0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STSFLD:
|
case opcode.STSFLD:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.static.Set(int(parameter[0]), item)
|
ctx.static.Set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.LDLOC0, opcode.LDLOC1, opcode.LDLOC2, opcode.LDLOC3, opcode.LDLOC4, opcode.LDLOC5, opcode.LDLOC6:
|
case opcode.LDLOC0, opcode.LDLOC1, opcode.LDLOC2, opcode.LDLOC3, opcode.LDLOC4, opcode.LDLOC5, opcode.LDLOC6:
|
||||||
item := ctx.local.Get(int(op - opcode.LDLOC0))
|
item := ctx.local.Get(int(op - opcode.LDLOC0))
|
||||||
|
@ -651,11 +656,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STLOC0, opcode.STLOC1, opcode.STLOC2, opcode.STLOC3, opcode.STLOC4, opcode.STLOC5, opcode.STLOC6:
|
case opcode.STLOC0, opcode.STLOC1, opcode.STLOC2, opcode.STLOC3, opcode.STLOC4, opcode.STLOC5, opcode.STLOC6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.local.Set(int(op-opcode.STLOC0), item)
|
ctx.local.Set(int(op-opcode.STLOC0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STLOC:
|
case opcode.STLOC:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.local.Set(int(parameter[0]), item)
|
ctx.local.Set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.LDARG0, opcode.LDARG1, opcode.LDARG2, opcode.LDARG3, opcode.LDARG4, opcode.LDARG5, opcode.LDARG6:
|
case opcode.LDARG0, opcode.LDARG1, opcode.LDARG2, opcode.LDARG3, opcode.LDARG4, opcode.LDARG5, opcode.LDARG6:
|
||||||
item := ctx.arguments.Get(int(op - opcode.LDARG0))
|
item := ctx.arguments.Get(int(op - opcode.LDARG0))
|
||||||
|
@ -667,11 +672,11 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.STARG0, opcode.STARG1, opcode.STARG2, opcode.STARG3, opcode.STARG4, opcode.STARG5, opcode.STARG6:
|
case opcode.STARG0, opcode.STARG1, opcode.STARG2, opcode.STARG3, opcode.STARG4, opcode.STARG5, opcode.STARG6:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.arguments.Set(int(op-opcode.STARG0), item)
|
ctx.arguments.Set(int(op-opcode.STARG0), item, &v.refs)
|
||||||
|
|
||||||
case opcode.STARG:
|
case opcode.STARG:
|
||||||
item := v.estack.Pop().Item()
|
item := v.estack.Pop().Item()
|
||||||
ctx.arguments.Set(int(parameter[0]), item)
|
ctx.arguments.Set(int(parameter[0]), item, &v.refs)
|
||||||
|
|
||||||
case opcode.NEWBUFFER:
|
case opcode.NEWBUFFER:
|
||||||
n := toInt(v.estack.Pop().BigInt())
|
n := toInt(v.estack.Pop().BigInt())
|
||||||
|
@ -887,12 +892,12 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
case opcode.INC:
|
case opcode.INC:
|
||||||
x := v.estack.Pop().BigInt()
|
x := v.estack.Pop().BigInt()
|
||||||
a := new(big.Int).Add(x, big.NewInt(1))
|
a := new(big.Int).Add(x, bigOne)
|
||||||
v.estack.PushItem(stackitem.NewBigInteger(a))
|
v.estack.PushItem(stackitem.NewBigInteger(a))
|
||||||
|
|
||||||
case opcode.DEC:
|
case opcode.DEC:
|
||||||
x := v.estack.Pop().BigInt()
|
x := v.estack.Pop().BigInt()
|
||||||
a := new(big.Int).Sub(x, big.NewInt(1))
|
a := new(big.Int).Sub(x, bigOne)
|
||||||
v.estack.PushItem(stackitem.NewBigInteger(a))
|
v.estack.PushItem(stackitem.NewBigInteger(a))
|
||||||
|
|
||||||
case opcode.ADD:
|
case opcode.ADD:
|
||||||
|
@ -1527,14 +1532,14 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
|
||||||
|
|
||||||
func (v *VM) unloadContext(ctx *Context) {
|
func (v *VM) unloadContext(ctx *Context) {
|
||||||
if ctx.local != nil {
|
if ctx.local != nil {
|
||||||
ctx.local.Clear()
|
ctx.local.Clear(&v.refs)
|
||||||
}
|
}
|
||||||
if ctx.arguments != nil {
|
if ctx.arguments != nil {
|
||||||
ctx.arguments.Clear()
|
ctx.arguments.Clear(&v.refs)
|
||||||
}
|
}
|
||||||
currCtx := v.Context()
|
currCtx := v.Context()
|
||||||
if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static {
|
if ctx.static != nil && currCtx != nil && ctx.static != currCtx.static {
|
||||||
ctx.static.Clear()
|
ctx.static.Clear(&v.refs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue