Merge pull request #1703 from nspcc-dev/initials_for_natives

core: store native contracts' initial values in the DB
This commit is contained in:
Roman Khimov 2021-02-05 15:32:05 +03:00 committed by GitHub
commit cdfc7fc8fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 180 additions and 123 deletions

View file

@ -118,7 +118,7 @@ func (chain *FakeChain) GetBaseExecFee() int64 {
// GetStoragePrice implements Policer interface. // GetStoragePrice implements Policer interface.
func (chain *FakeChain) GetStoragePrice() int64 { func (chain *FakeChain) GetStoragePrice() int64 {
return native.StoragePrice return native.DefaultStoragePrice
} }
// GetMaxVerificationGAS implements Policer interface. // GetMaxVerificationGAS implements Policer interface.

View file

@ -641,7 +641,7 @@ func (bc *Blockchain) storeBlock(block *block.Block, txpool *mempool.Pool) error
systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx) systemInterop := bc.newInteropContext(trigger.Application, cache, block, tx)
v := systemInterop.SpawnVM() v := systemInterop.SpawnVM()
v.LoadScriptWithFlags(tx.Script, callflag.All) v.LoadScriptWithFlags(tx.Script, callflag.All)
v.SetPriceGetter(bc.getPrice) v.SetPriceGetter(systemInterop.GetPrice)
v.LoadToken = contract.LoadToken(systemInterop) v.LoadToken = contract.LoadToken(systemInterop)
v.GasLimit = tx.SystemFee v.GasLimit = tx.SystemFee
@ -849,7 +849,7 @@ func (bc *Blockchain) runPersist(script []byte, block *block.Block, cache *dao.C
systemInterop := bc.newInteropContext(trig, cache, block, nil) systemInterop := bc.newInteropContext(trig, cache, block, nil)
v := systemInterop.SpawnVM() v := systemInterop.SpawnVM()
v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall) v.LoadScriptWithFlags(script, callflag.WriteStates|callflag.AllowCall)
v.SetPriceGetter(bc.getPrice) v.SetPriceGetter(systemInterop.GetPrice)
if err := v.Run(); err != nil { if err := v.Run(); err != nil {
return nil, fmt.Errorf("VM has failed: %w", err) return nil, fmt.Errorf("VM has failed: %w", err)
} else if _, err := systemInterop.DAO.Persist(); err != nil { } else if _, err := systemInterop.DAO.Persist(); err != nil {
@ -1718,7 +1718,7 @@ func (bc *Blockchain) GetTestVM(t trigger.Type, tx *transaction.Transaction, b *
d.MPT = nil d.MPT = nil
systemInterop := bc.newInteropContext(t, d, b, tx) systemInterop := bc.newInteropContext(t, d, b, tx)
vm := systemInterop.SpawnVM() vm := systemInterop.SpawnVM()
vm.SetPriceGetter(bc.getPrice) vm.SetPriceGetter(systemInterop.GetPrice)
vm.LoadToken = contract.LoadToken(systemInterop) vm.LoadToken = contract.LoadToken(systemInterop)
return vm return vm
} }
@ -1794,7 +1794,7 @@ func (bc *Blockchain) verifyHashAgainstScript(hash util.Uint160, witness *transa
} }
vm := interopCtx.SpawnVM() vm := interopCtx.SpawnVM()
vm.SetPriceGetter(bc.getPrice) vm.SetPriceGetter(interopCtx.GetPrice)
vm.LoadToken = contract.LoadToken(interopCtx) vm.LoadToken = contract.LoadToken(interopCtx)
vm.GasLimit = gas vm.GasLimit = gas
if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil { if err := bc.initVerificationVM(interopCtx, hash, witness); err != nil {
@ -1938,6 +1938,9 @@ func (bc *Blockchain) GetMaxVerificationGAS() int64 {
// GetStoragePrice returns current storage price. // GetStoragePrice returns current storage price.
func (bc *Blockchain) GetStoragePrice() int64 { func (bc *Blockchain) GetStoragePrice() int64 {
if bc.BlockHeight() == 0 {
return native.DefaultStoragePrice
}
return bc.contracts.Policy.GetStoragePriceInternal(bc.dao) return bc.contracts.Policy.GetStoragePriceInternal(bc.dao)
} }

View file

@ -1,13 +1,15 @@
package fee package fee
import ( import (
"github.com/nspcc-dev/neo-go/pkg/core/interop/crypto"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/vm" "github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/emit" "github.com/nspcc-dev/neo-go/pkg/vm/emit"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode" "github.com/nspcc-dev/neo-go/pkg/vm/opcode"
) )
// ECDSAVerifyPrice is a gas price of a single verification.
const ECDSAVerifyPrice = 1 << 15
// Calculate returns network fee for transaction // Calculate returns network fee for transaction
func Calculate(base int64, script []byte) (int64, int) { func Calculate(base int64, script []byte) (int64, int) {
var ( var (
@ -16,13 +18,13 @@ func Calculate(base int64, script []byte) (int64, int) {
) )
if vm.IsSignatureContract(script) { if vm.IsSignatureContract(script) {
size += 67 + io.GetVarSize(script) size += 67 + io.GetVarSize(script)
netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*crypto.ECDSAVerifyPrice netFee += Opcode(base, opcode.PUSHDATA1, opcode.PUSHNULL, opcode.PUSHDATA1) + base*ECDSAVerifyPrice
} else if m, pubs, ok := vm.ParseMultiSigContract(script); ok { } else if m, pubs, ok := vm.ParseMultiSigContract(script); ok {
n := len(pubs) n := len(pubs)
sizeInv := 66 * m sizeInv := 66 * m
size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script) size += io.GetVarSize(sizeInv) + sizeInv + io.GetVarSize(script)
netFee += calculateMultisig(base, m) + calculateMultisig(base, n) netFee += calculateMultisig(base, m) + calculateMultisig(base, n)
netFee += Opcode(base, opcode.PUSHNULL) + base*crypto.ECDSAVerifyPrice*int64(n) netFee += Opcode(base, opcode.PUSHNULL) + base*ECDSAVerifyPrice*int64(n)
} else { } else {
// We can support more contract types in the future. // We can support more contract types in the future.
} }

View file

@ -1,12 +0,0 @@
package core
import (
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/vm"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// getPrice returns a price for executing op with the provided parameter.
func (bc *Blockchain) getPrice(v *vm.VM, op opcode.Opcode, parameter []byte) int64 {
return fee.Opcode(bc.GetBaseExecFee(), op)
}

View file

@ -199,7 +199,7 @@ func (ic *Context) GetFunction(id uint32) *Function {
// BaseExecFee represents factor to multiply syscall prices with. // BaseExecFee represents factor to multiply syscall prices with.
func (ic *Context) BaseExecFee() int64 { func (ic *Context) BaseExecFee() int64 {
if ic.Chain == nil { if ic.Chain == nil || (ic.Block != nil && ic.Block.Index == 0) {
return DefaultBaseExecFee return DefaultBaseExecFee
} }
return ic.Chain.GetPolicer().GetBaseExecFee() return ic.Chain.GetPolicer().GetBaseExecFee()

View file

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/btcec"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/crypto" "github.com/nspcc-dev/neo-go/pkg/crypto"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/crypto/hash"
@ -15,9 +16,6 @@ import (
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
// ECDSAVerifyPrice is a gas price of a single verification.
const ECDSAVerifyPrice = 1 << 15
// ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve. // ECDSASecp256r1Verify checks ECDSA signature using Secp256r1 elliptic curve.
func ECDSASecp256r1Verify(ic *interop.Context) error { func ECDSASecp256r1Verify(ic *interop.Context) error {
return ecdsaVerify(ic, elliptic.P256()) return ecdsaVerify(ic, elliptic.P256())
@ -69,7 +67,7 @@ func ecdsaCheckMultisig(ic *interop.Context, curve elliptic.Curve) error {
if err != nil { if err != nil {
return fmt.Errorf("wrong parameters: %w", err) return fmt.Errorf("wrong parameters: %w", err)
} }
if !ic.VM.AddGas(ic.BaseExecFee() * ECDSAVerifyPrice * int64(len(pkeys))) { if !ic.VM.AddGas(ic.BaseExecFee() * fee.ECDSAVerifyPrice * int64(len(pkeys))) {
return errors.New("gas limit exceeded") return errors.New("gas limit exceeded")
} }
sigs, err := ic.VM.Estack().PopSigElements() sigs, err := ic.VM.Estack().PopSigElements()

View file

@ -7,6 +7,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/core/transaction" "github.com/nspcc-dev/neo-go/pkg/core/transaction"
@ -247,7 +248,7 @@ func testCurveCHECKMULTISIGBad(t *testing.T, isR1 bool) {
t.Run("1_2 too many signatures", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, true, 2, []int{0}, []int{0, 1}) }) t.Run("1_2 too many signatures", func(t *testing.T) { testCHECKMULTISIGBad(t, isR1, true, 2, []int{0}, []int{0, 1}) })
t.Run("gas limit exceeded", func(t *testing.T) { t.Run("gas limit exceeded", func(t *testing.T) {
v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0}) v := initCHECKMULTISIGVM(t, isR1, 1, []int{0}, []int{0})
v.GasLimit = ECDSAVerifyPrice - 1 v.GasLimit = fee.ECDSAVerifyPrice - 1
require.Error(t, v.Run()) require.Error(t, v.Run())
}) })

View file

@ -0,0 +1,11 @@
package interop
import (
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/vm/opcode"
)
// GetPrice returns a price for executing op with the provided parameter.
func (ic *Context) GetPrice(op opcode.Opcode, parameter []byte) int64 {
return fee.Opcode(ic.BaseExecFee(), op)
}

View file

@ -195,23 +195,23 @@ func TestStoragePut(t *testing.T) {
} }
t.Run("create, not enough gas", func(t *testing.T) { t.Run("create, not enough gas", func(t *testing.T) {
initVM(t, []byte{1}, []byte{2, 3}, 2*native.StoragePrice) initVM(t, []byte{1}, []byte{2, 3}, 2*native.DefaultStoragePrice)
err := storagePut(ic) err := storagePut(ic)
require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err) require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err)
}) })
initVM(t, []byte{4}, []byte{5, 6}, 3*native.StoragePrice) initVM(t, []byte{4}, []byte{5, 6}, 3*native.DefaultStoragePrice)
require.NoError(t, storagePut(ic)) require.NoError(t, storagePut(ic))
t.Run("update", func(t *testing.T) { t.Run("update", func(t *testing.T) {
t.Run("not enough gas", func(t *testing.T) { t.Run("not enough gas", func(t *testing.T) {
initVM(t, []byte{4}, []byte{5, 6, 7, 8}, native.StoragePrice) initVM(t, []byte{4}, []byte{5, 6, 7, 8}, native.DefaultStoragePrice)
err := storagePut(ic) err := storagePut(ic)
require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err) require.True(t, errors.Is(err, errGasLimitExceeded), "got: %v", err)
}) })
initVM(t, []byte{4}, []byte{5, 6, 7, 8}, 3*native.StoragePrice) initVM(t, []byte{4}, []byte{5, 6, 7, 8}, 3*native.DefaultStoragePrice)
require.NoError(t, storagePut(ic)) require.NoError(t, storagePut(ic))
initVM(t, []byte{4}, []byte{5, 6}, native.StoragePrice) initVM(t, []byte{4}, []byte{5, 6}, native.DefaultStoragePrice)
require.NoError(t, storagePut(ic)) require.NoError(t, storagePut(ic))
}) })

View file

@ -8,6 +8,7 @@ package core
*/ */
import ( import (
"github.com/nspcc-dev/neo-go/pkg/core/fee"
"github.com/nspcc-dev/neo-go/pkg/core/interop" "github.com/nspcc-dev/neo-go/pkg/core/interop"
"github.com/nspcc-dev/neo-go/pkg/core/interop/binary" "github.com/nspcc-dev/neo-go/pkg/core/interop/binary"
"github.com/nspcc-dev/neo-go/pkg/core/interop/contract" "github.com/nspcc-dev/neo-go/pkg/core/interop/contract"
@ -88,9 +89,9 @@ var systemInterops = []interop.Function{
var neoInterops = []interop.Function{ var neoInterops = []interop.Function{
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify, {Name: interopnames.NeoCryptoVerifyWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1Verify,
Price: crypto.ECDSAVerifyPrice, ParamCount: 3}, Price: fee.ECDSAVerifyPrice, ParamCount: 3},
{Name: interopnames.NeoCryptoVerifyWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1Verify, {Name: interopnames.NeoCryptoVerifyWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1Verify,
Price: crypto.ECDSAVerifyPrice, ParamCount: 3}, Price: fee.ECDSAVerifyPrice, ParamCount: 3},
{Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256r1, Func: crypto.ECDSASecp256r1CheckMultisig, Price: 0, ParamCount: 3},
{Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0, ParamCount: 3}, {Name: interopnames.NeoCryptoCheckMultisigWithECDsaSecp256k1, Func: crypto.ECDSASecp256k1CheckMultisig, Price: 0, ParamCount: 3},
{Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1}, {Name: interopnames.NeoCryptoSHA256, Func: crypto.Sha256, Price: 1 << 15, ParamCount: 1},

View file

@ -33,9 +33,6 @@ type Management struct {
contracts map[util.Uint160]*state.Contract contracts map[util.Uint160]*state.Contract
} }
// StoragePrice is the price to pay for 1 byte of storage.
const StoragePrice = 100000
const ( const (
managementContractID = -1 managementContractID = -1
@ -386,7 +383,7 @@ func (m *Management) getMinimumDeploymentFee(ic *interop.Context, args []stackit
// GetMinimumDeploymentFee returns the minimum required fee for contract deploy. // GetMinimumDeploymentFee returns the minimum required fee for contract deploy.
func (m *Management) GetMinimumDeploymentFee(dao dao.DAO) int64 { func (m *Management) GetMinimumDeploymentFee(dao dao.DAO) int64 {
return int64(getUint32WithKey(m.ContractID, dao, keyMinimumDeploymentFee, defaultMinimumDeploymentFee)) return getIntWithKey(m.ContractID, dao, keyMinimumDeploymentFee)
} }
func (m *Management) setMinimumDeploymentFee(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (m *Management) setMinimumDeploymentFee(ic *interop.Context, args []stackitem.Item) stackitem.Item {
@ -397,7 +394,7 @@ func (m *Management) setMinimumDeploymentFee(ic *interop.Context, args []stackit
if !m.NEO.checkCommittee(ic) { if !m.NEO.checkCommittee(ic) {
panic("invalid committee signature") panic("invalid committee signature")
} }
err := setUint32WithKey(m.ContractID, ic.DAO, keyMinimumDeploymentFee, value) err := setIntWithKey(m.ContractID, ic.DAO, keyMinimumDeploymentFee, int64(value))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -508,7 +505,10 @@ func (m *Management) PostPersist(ic *interop.Context) error {
// Initialize implements Contract interface. // Initialize implements Contract interface.
func (m *Management) Initialize(ic *interop.Context) error { func (m *Management) Initialize(ic *interop.Context) error {
return setUint32WithKey(m.ContractID, ic.DAO, keyMinimumDeploymentFee, defaultMinimumDeploymentFee) if err := setIntWithKey(m.ContractID, ic.DAO, keyMinimumDeploymentFee, defaultMinimumDeploymentFee); err != nil {
return err
}
return setIntWithKey(m.ContractID, ic.DAO, keyNextAvailableID, 1)
} }
// PutContractState saves given contract state into given DAO. // PutContractState saves given contract state into given DAO.
@ -525,16 +525,14 @@ func (m *Management) PutContractState(d dao.DAO, cs *state.Contract) error {
} }
func (m *Management) getNextContractID(d dao.DAO) (int32, error) { func (m *Management) getNextContractID(d dao.DAO) (int32, error) {
var id = big.NewInt(1)
si := d.GetStorageItem(m.ContractID, keyNextAvailableID) si := d.GetStorageItem(m.ContractID, keyNextAvailableID)
if si != nil { if si == nil {
id = bigint.FromBytes(si.Value) return 0, errors.New("nextAvailableID is not initialized")
} else {
si = new(state.StorageItem)
si.Value = make([]byte, 0, 2)
} }
id := bigint.FromBytes(si.Value)
ret := int32(id.Int64()) ret := int32(id.Int64())
id.Add(id, big.NewInt(1)) id.Add(id, intOne)
si.Value = bigint.ToPreallocatedBytes(id, si.Value) si.Value = bigint.ToPreallocatedBytes(id, si.Value)
return ret, d.PutStorageItem(m.ContractID, keyNextAvailableID, si) return ret, d.PutStorageItem(m.ContractID, keyNextAvailableID, si)
} }

View file

@ -5,6 +5,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/config/netmode" "github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "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/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest" "github.com/nspcc-dev/neo-go/pkg/smartcontract/manifest"
@ -15,7 +16,8 @@ import (
func TestDeployGetUpdateDestroyContract(t *testing.T) { func TestDeployGetUpdateDestroyContract(t *testing.T) {
mgmt := newManagement() mgmt := newManagement()
d := dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false) d := dao.NewCached(dao.NewSimple(storage.NewMemoryStore(), netmode.UnitTestNet, false))
mgmt.Initialize(&interop.Context{DAO: d})
script := []byte{1} script := []byte{1}
sender := util.Uint160{1, 2, 3} sender := util.Uint160{1, 2, 3}
ne, err := nef.NewFile(script) ne, err := nef.NewFile(script)

View file

@ -172,11 +172,12 @@ func (n *NameService) Metadata() *interop.ContractMD {
// Initialize implements interop.Contract interface. // Initialize implements interop.Contract interface.
func (n *NameService) Initialize(ic *interop.Context) error { func (n *NameService) Initialize(ic *interop.Context) error {
si := &state.StorageItem{Value: bigint.ToBytes(big.NewInt(DefaultDomainPrice))} if err := n.nonfungible.Initialize(ic); err != nil {
if err := ic.DAO.PutStorageItem(n.ContractID, []byte{prefixDomainPrice}, si); err != nil { return err
}
if err := setIntWithKey(n.ContractID, ic.DAO, []byte{prefixDomainPrice}, DefaultDomainPrice); err != nil {
return err return err
} }
roots := stringList{} roots := stringList{}
return putSerializableToDAO(n.ContractID, ic.DAO, []byte{prefixRoots}, &roots) return putSerializableToDAO(n.ContractID, ic.DAO, []byte{prefixRoots}, &roots)
} }

View file

@ -50,8 +50,6 @@ const (
var ( var (
nftTotalSupplyKey = []byte{prefixNFTTotalSupply} nftTotalSupplyKey = []byte{prefixNFTTotalSupply}
intOne = big.NewInt(1)
) )
func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfungible { func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfungible {
@ -120,6 +118,11 @@ func newNonFungible(name string, id int32, symbol string, decimals byte) *nonfun
return n return n
} }
// Initialize implements interop.Contract interface.
func (n nonfungible) Initialize(ic *interop.Context) error {
return setIntWithKey(n.ContractID, ic.DAO, nftTotalSupplyKey, 0)
}
func (n *nonfungible) symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item { func (n *nonfungible) symbol(_ *interop.Context, _ []stackitem.Item) stackitem.Item {
return stackitem.NewByteArray([]byte(n.tokenSymbol)) return stackitem.NewByteArray([]byte(n.tokenSymbol))
} }
@ -135,7 +138,7 @@ func (n *nonfungible) totalSupply(ic *interop.Context, _ []stackitem.Item) stack
func (n *nonfungible) TotalSupply(d dao.DAO) *big.Int { func (n *nonfungible) TotalSupply(d dao.DAO) *big.Int {
si := d.GetStorageItem(n.ContractID, nftTotalSupplyKey) si := d.GetStorageItem(n.ContractID, nftTotalSupplyKey)
if si == nil { if si == nil {
return big.NewInt(0) panic(errors.New("total supply is not initialized"))
} }
return bigint.FromBytes(si.Value) return bigint.FromBytes(si.Value)
} }

View file

@ -108,6 +108,11 @@ func (n *Notary) Metadata() *interop.ContractMD {
// Initialize initializes Notary native contract and implements Contract interface. // Initialize initializes Notary native contract and implements Contract interface.
func (n *Notary) Initialize(ic *interop.Context) error { func (n *Notary) Initialize(ic *interop.Context) error {
err := setIntWithKey(n.ContractID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta)
if err != nil {
return err
}
n.isValid = true n.isValid = true
n.maxNotValidBeforeDelta = defaultMaxNotValidBeforeDelta n.maxNotValidBeforeDelta = defaultMaxNotValidBeforeDelta
return nil return nil
@ -166,7 +171,7 @@ func (n *Notary) PostPersist(ic *interop.Context) error {
return nil return nil
} }
n.maxNotValidBeforeDelta = getUint32WithKey(n.ContractID, ic.DAO, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta) n.maxNotValidBeforeDelta = uint32(getIntWithKey(n.ContractID, ic.DAO, maxNotValidBeforeDeltaKey))
n.isValid = true n.isValid = true
return nil return nil
} }
@ -379,7 +384,7 @@ func (n *Notary) GetMaxNotValidBeforeDelta(dao dao.DAO) uint32 {
if n.isValid { if n.isValid {
return n.maxNotValidBeforeDelta return n.maxNotValidBeforeDelta
} }
return getUint32WithKey(n.ContractID, dao, maxNotValidBeforeDeltaKey, defaultMaxNotValidBeforeDelta) return uint32(getIntWithKey(n.ContractID, dao, maxNotValidBeforeDeltaKey))
} }
// setMaxNotValidBeforeDelta is Notary contract method and sets the maximum NotValidBefore delta. // setMaxNotValidBeforeDelta is Notary contract method and sets the maximum NotValidBefore delta.
@ -393,7 +398,7 @@ func (n *Notary) setMaxNotValidBeforeDelta(ic *interop.Context, args []stackitem
} }
n.lock.Lock() n.lock.Lock()
defer n.lock.Unlock() defer n.lock.Unlock()
err := setUint32WithKey(n.ContractID, ic.DAO, maxNotValidBeforeDeltaKey, value) err := setIntWithKey(n.ContractID, ic.DAO, maxNotValidBeforeDeltaKey, int64(value))
if err != nil { if err != nil {
panic(fmt.Errorf("failed to put value into the storage: %w", err)) panic(fmt.Errorf("failed to put value into the storage: %w", err))
} }

View file

@ -20,6 +20,7 @@ import (
"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/crypto/hash" "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/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/smartcontract" "github.com/nspcc-dev/neo-go/pkg/smartcontract"
"github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag" "github.com/nspcc-dev/neo-go/pkg/smartcontract/callflag"
@ -201,8 +202,7 @@ func (o *Oracle) Metadata() *interop.ContractMD {
// Initialize initializes Oracle contract. // Initialize initializes Oracle contract.
func (o *Oracle) Initialize(ic *interop.Context) error { func (o *Oracle) Initialize(ic *interop.Context) error {
si := &state.StorageItem{Value: make([]byte, 8)} // uint64(0) LE return setIntWithKey(o.ContractID, ic.DAO, prefixRequestID, 0)
return ic.DAO.PutStorageItem(o.ContractID, prefixRequestID, si)
} }
func getResponse(tx *transaction.Transaction) *transaction.OracleResponse { func getResponse(tx *transaction.Transaction) *transaction.OracleResponse {
@ -302,8 +302,10 @@ func (o *Oracle) RequestInternal(ic *interop.Context, url string, filter *string
callingHash := ic.VM.GetCallingScriptHash() callingHash := ic.VM.GetCallingScriptHash()
o.GAS.mint(ic, o.Hash, gas, false) o.GAS.mint(ic, o.Hash, gas, false)
si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID) si := ic.DAO.GetStorageItem(o.ContractID, prefixRequestID)
id := binary.LittleEndian.Uint64(si.Value) + 1 itemID := bigint.FromBytes(si.Value)
binary.LittleEndian.PutUint64(si.Value, id) id := itemID.Uint64()
itemID.Add(itemID, intOne)
si.Value = bigint.ToPreallocatedBytes(itemID, si.Value)
if err := ic.DAO.PutStorageItem(o.ContractID, prefixRequestID, si); err != nil { if err := ic.DAO.PutStorageItem(o.ContractID, prefixRequestID, si); err != nil {
return err return err
} }
@ -432,7 +434,7 @@ func (o *Oracle) getRequests(d dao.DAO) (map[uint64]*state.OracleRequest, error)
if r.Err != nil { if r.Err != nil {
return nil, r.Err return nil, r.Err
} }
id := binary.LittleEndian.Uint64([]byte(k)) id := binary.BigEndian.Uint64([]byte(k))
reqs[id] = req reqs[id] = req
} }
return reqs, nil return reqs, nil
@ -441,7 +443,7 @@ func (o *Oracle) getRequests(d dao.DAO) (map[uint64]*state.OracleRequest, error)
func makeRequestKey(id uint64) []byte { func makeRequestKey(id uint64) []byte {
k := make([]byte, 9) k := make([]byte, 9)
k[0] = prefixRequest[0] k[0] = prefixRequest[0]
binary.LittleEndian.PutUint64(k[1:], id) binary.BigEndian.PutUint64(k[1:], id)
return k return k
} }

View file

@ -29,6 +29,9 @@ const (
defaultFeePerByte = 1000 defaultFeePerByte = 1000
defaultMaxVerificationGas = 50000000 defaultMaxVerificationGas = 50000000
defaultMaxBlockSystemFee = 9000 * GASFactor defaultMaxBlockSystemFee = 9000 * GASFactor
// DefaultStoragePrice is the price to pay for 1 byte of storage.
DefaultStoragePrice = 100000
// minBlockSystemFee is the minimum allowed system fee per block. // minBlockSystemFee is the minimum allowed system fee per block.
minBlockSystemFee = 4007600 minBlockSystemFee = 4007600
// maxExecFeeFactor is the maximum allowed execution fee factor. // maxExecFeeFactor is the maximum allowed execution fee factor.
@ -163,6 +166,25 @@ func (p *Policy) Metadata() *interop.ContractMD {
// Initialize initializes Policy native contract and implements Contract interface. // Initialize initializes Policy native contract and implements Contract interface.
func (p *Policy) Initialize(ic *interop.Context) error { func (p *Policy) Initialize(ic *interop.Context) error {
if err := setIntWithKey(p.ContractID, ic.DAO, maxTransactionsPerBlockKey, defaultMaxTransactionsPerBlock); err != nil {
return err
}
if err := setIntWithKey(p.ContractID, ic.DAO, feePerByteKey, defaultFeePerByte); err != nil {
return err
}
if err := setIntWithKey(p.ContractID, ic.DAO, maxBlockSizeKey, defaultMaxBlockSize); err != nil {
return err
}
if err := setIntWithKey(p.ContractID, ic.DAO, maxBlockSystemFeeKey, defaultMaxBlockSystemFee); err != nil {
return err
}
if err := setIntWithKey(p.ContractID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor); err != nil {
return err
}
if err := setIntWithKey(p.ContractID, ic.DAO, storagePriceKey, DefaultStoragePrice); err != nil {
return err
}
p.isValid = true p.isValid = true
p.maxTransactionsPerBlock = defaultMaxTransactionsPerBlock p.maxTransactionsPerBlock = defaultMaxTransactionsPerBlock
p.maxBlockSize = defaultMaxBlockSize p.maxBlockSize = defaultMaxBlockSize
@ -170,7 +192,7 @@ func (p *Policy) Initialize(ic *interop.Context) error {
p.feePerByte = defaultFeePerByte p.feePerByte = defaultFeePerByte
p.maxBlockSystemFee = defaultMaxBlockSystemFee p.maxBlockSystemFee = defaultMaxBlockSystemFee
p.maxVerificationGas = defaultMaxVerificationGas p.maxVerificationGas = defaultMaxVerificationGas
p.storagePrice = StoragePrice p.storagePrice = DefaultStoragePrice
p.blockedAccounts = make([]util.Uint160, 0) p.blockedAccounts = make([]util.Uint160, 0)
return nil return nil
@ -189,13 +211,13 @@ func (p *Policy) PostPersist(ic *interop.Context) error {
return nil return nil
} }
p.maxTransactionsPerBlock = getUint32WithKey(p.ContractID, ic.DAO, maxTransactionsPerBlockKey, defaultMaxTransactionsPerBlock) p.maxTransactionsPerBlock = uint32(getIntWithKey(p.ContractID, ic.DAO, maxTransactionsPerBlockKey))
p.maxBlockSize = getUint32WithKey(p.ContractID, ic.DAO, maxBlockSizeKey, defaultMaxBlockSize) p.maxBlockSize = uint32(getIntWithKey(p.ContractID, ic.DAO, maxBlockSizeKey))
p.execFeeFactor = getUint32WithKey(p.ContractID, ic.DAO, execFeeFactorKey, defaultExecFeeFactor) p.execFeeFactor = uint32(getIntWithKey(p.ContractID, ic.DAO, execFeeFactorKey))
p.feePerByte = getInt64WithKey(p.ContractID, ic.DAO, feePerByteKey, defaultFeePerByte) p.feePerByte = getIntWithKey(p.ContractID, ic.DAO, feePerByteKey)
p.maxBlockSystemFee = getInt64WithKey(p.ContractID, ic.DAO, maxBlockSystemFeeKey, defaultMaxBlockSystemFee) p.maxBlockSystemFee = getIntWithKey(p.ContractID, ic.DAO, maxBlockSystemFeeKey)
p.maxVerificationGas = defaultMaxVerificationGas p.maxVerificationGas = defaultMaxVerificationGas
p.storagePrice = getUint32WithKey(p.ContractID, ic.DAO, storagePriceKey, StoragePrice) p.storagePrice = uint32(getIntWithKey(p.ContractID, ic.DAO, storagePriceKey))
p.blockedAccounts = make([]util.Uint160, 0) p.blockedAccounts = make([]util.Uint160, 0)
siMap, err := ic.DAO.GetStorageItemsWithPrefix(p.ContractID, []byte{blockedAccountPrefix}) siMap, err := ic.DAO.GetStorageItemsWithPrefix(p.ContractID, []byte{blockedAccountPrefix})
@ -231,7 +253,7 @@ func (p *Policy) GetMaxTransactionsPerBlockInternal(dao dao.DAO) uint32 {
if p.isValid { if p.isValid {
return p.maxTransactionsPerBlock return p.maxTransactionsPerBlock
} }
return getUint32WithKey(p.ContractID, dao, maxTransactionsPerBlockKey, defaultMaxTransactionsPerBlock) return uint32(getIntWithKey(p.ContractID, dao, maxTransactionsPerBlockKey))
} }
// getMaxBlockSize is Policy contract method and returns maximum block size. // getMaxBlockSize is Policy contract method and returns maximum block size.
@ -246,7 +268,7 @@ func (p *Policy) GetMaxBlockSizeInternal(dao dao.DAO) uint32 {
if p.isValid { if p.isValid {
return p.maxBlockSize return p.maxBlockSize
} }
return getUint32WithKey(p.ContractID, dao, maxBlockSizeKey, defaultMaxBlockSize) return uint32(getIntWithKey(p.ContractID, dao, maxBlockSizeKey))
} }
// getFeePerByte is Policy contract method and returns required transaction's fee // getFeePerByte is Policy contract method and returns required transaction's fee
@ -262,7 +284,7 @@ func (p *Policy) GetFeePerByteInternal(dao dao.DAO) int64 {
if p.isValid { if p.isValid {
return p.feePerByte return p.feePerByte
} }
return getInt64WithKey(p.ContractID, dao, feePerByteKey, defaultFeePerByte) return getIntWithKey(p.ContractID, dao, feePerByteKey)
} }
// GetMaxVerificationGas returns maximum gas allowed to be burned during verificaion. // GetMaxVerificationGas returns maximum gas allowed to be burned during verificaion.
@ -286,7 +308,7 @@ func (p *Policy) GetMaxBlockSystemFeeInternal(dao dao.DAO) int64 {
if p.isValid { if p.isValid {
return p.maxBlockSystemFee return p.maxBlockSystemFee
} }
return getInt64WithKey(p.ContractID, dao, maxBlockSystemFeeKey, defaultMaxBlockSystemFee) return getIntWithKey(p.ContractID, dao, maxBlockSystemFeeKey)
} }
func (p *Policy) getExecFeeFactor(ic *interop.Context, _ []stackitem.Item) stackitem.Item { func (p *Policy) getExecFeeFactor(ic *interop.Context, _ []stackitem.Item) stackitem.Item {
@ -300,7 +322,7 @@ func (p *Policy) GetExecFeeFactorInternal(d dao.DAO) int64 {
if p.isValid { if p.isValid {
return int64(p.execFeeFactor) return int64(p.execFeeFactor)
} }
return int64(getUint32WithKey(p.ContractID, d, execFeeFactorKey, defaultExecFeeFactor)) return getIntWithKey(p.ContractID, d, execFeeFactorKey)
} }
func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) stackitem.Item {
@ -313,7 +335,7 @@ func (p *Policy) setExecFeeFactor(ic *interop.Context, args []stackitem.Item) st
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setUint32WithKey(p.ContractID, ic.DAO, execFeeFactorKey, uint32(value)) err := setIntWithKey(p.ContractID, ic.DAO, execFeeFactorKey, int64(value))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -356,7 +378,7 @@ func (p *Policy) GetStoragePriceInternal(d dao.DAO) int64 {
if p.isValid { if p.isValid {
return int64(p.storagePrice) return int64(p.storagePrice)
} }
return int64(getUint32WithKey(p.ContractID, d, storagePriceKey, StoragePrice)) return getIntWithKey(p.ContractID, d, storagePriceKey)
} }
func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) stackitem.Item { func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) stackitem.Item {
@ -369,7 +391,7 @@ func (p *Policy) setStoragePrice(ic *interop.Context, args []stackitem.Item) sta
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setUint32WithKey(p.ContractID, ic.DAO, storagePriceKey, uint32(value)) err := setIntWithKey(p.ContractID, ic.DAO, storagePriceKey, int64(value))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -389,7 +411,7 @@ func (p *Policy) setMaxTransactionsPerBlock(ic *interop.Context, args []stackite
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setUint32WithKey(p.ContractID, ic.DAO, maxTransactionsPerBlockKey, value) err := setIntWithKey(p.ContractID, ic.DAO, maxTransactionsPerBlockKey, int64(value))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -408,7 +430,7 @@ func (p *Policy) setMaxBlockSize(ic *interop.Context, args []stackitem.Item) sta
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setUint32WithKey(p.ContractID, ic.DAO, maxBlockSizeKey, value) err := setIntWithKey(p.ContractID, ic.DAO, maxBlockSizeKey, int64(value))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -427,7 +449,7 @@ func (p *Policy) setFeePerByte(ic *interop.Context, args []stackitem.Item) stack
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setInt64WithKey(p.ContractID, ic.DAO, feePerByteKey, value) err := setIntWithKey(p.ContractID, ic.DAO, feePerByteKey, value)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -446,7 +468,7 @@ func (p *Policy) setMaxBlockSystemFee(ic *interop.Context, args []stackitem.Item
} }
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := setInt64WithKey(p.ContractID, ic.DAO, maxBlockSystemFeeKey, value) err := setIntWithKey(p.ContractID, ic.DAO, maxBlockSystemFeeKey, value)
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -468,7 +490,7 @@ func (p *Policy) blockAccount(ic *interop.Context, args []stackitem.Item) stacki
p.lock.Lock() p.lock.Lock()
defer p.lock.Unlock() defer p.lock.Unlock()
err := ic.DAO.PutStorageItem(p.ContractID, key, &state.StorageItem{ err := ic.DAO.PutStorageItem(p.ContractID, key, &state.StorageItem{
Value: []byte{0x01}, Value: []byte{},
}) })
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -2,15 +2,21 @@ package native
import ( import (
"encoding/binary" "encoding/binary"
"encoding/hex"
"fmt"
"math/big"
"github.com/nspcc-dev/neo-go/pkg/core/dao" "github.com/nspcc-dev/neo-go/pkg/core/dao"
"github.com/nspcc-dev/neo-go/pkg/core/state" "github.com/nspcc-dev/neo-go/pkg/core/state"
"github.com/nspcc-dev/neo-go/pkg/core/storage" "github.com/nspcc-dev/neo-go/pkg/core/storage"
"github.com/nspcc-dev/neo-go/pkg/encoding/bigint"
"github.com/nspcc-dev/neo-go/pkg/io" "github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem" "github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
) )
var intOne = big.NewInt(1)
func getSerializableFromDAO(id int32, d dao.DAO, key []byte, item io.Serializable) error { func getSerializableFromDAO(id int32, d dao.DAO, key []byte, item io.Serializable) error {
si := d.GetStorageItem(id, key) si := d.GetStorageItem(id, key)
if si == nil { if si == nil {
@ -64,6 +70,20 @@ func setUint32WithKey(id int32, dao dao.DAO, key []byte, value uint32) error {
return dao.PutStorageItem(id, key, si) return dao.PutStorageItem(id, key, si)
} }
func setIntWithKey(id int32, dao dao.DAO, key []byte, value int64) error {
si := &state.StorageItem{Value: bigint.ToBytes(big.NewInt(value))}
return dao.PutStorageItem(id, key, si)
}
func getIntWithKey(id int32, dao dao.DAO, key []byte) int64 {
si := dao.GetStorageItem(id, key)
if si == nil {
panic(fmt.Errorf("item with id = %d and key = %s is not initialized", id, hex.EncodeToString(key)))
}
return bigint.FromBytes(si.Value).Int64()
}
// makeUint160Key creates a key from account script hash. // makeUint160Key creates a key from account script hash.
func makeUint160Key(prefix byte, h util.Uint160) []byte { func makeUint160Key(prefix byte, h util.Uint160) []byte {
k := make([]byte, util.Uint160Size+1) k := make([]byte, util.Uint160Size+1)

View file

@ -124,7 +124,7 @@ func TestOracle_Request(t *testing.T) {
userData := []byte("custom info") userData := []byte("custom info")
txHash := putOracleRequest(t, cs.Hash, bc, "url", &filter, "handle", userData, gasForResponse) txHash := putOracleRequest(t, cs.Hash, bc, "url", &filter, "handle", userData, gasForResponse)
req, err := orc.GetRequestInternal(bc.dao, 1) req, err := orc.GetRequestInternal(bc.dao, 0)
require.NotNil(t, req) require.NotNil(t, req)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, txHash, req.OriginalTxID) require.Equal(t, txHash, req.OriginalTxID)
@ -136,7 +136,7 @@ func TestOracle_Request(t *testing.T) {
idList, err := orc.GetIDListInternal(bc.dao, "url") idList, err := orc.GetIDListInternal(bc.dao, "url")
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, &native.IDList{1}, idList) require.Equal(t, &native.IDList{0}, idList)
// Finish. // Finish.
priv, err := keys.NewPrivateKey() priv, err := keys.NewPrivateKey()
@ -161,7 +161,7 @@ func TestOracle_Request(t *testing.T) {
require.True(t, errors.Is(err, native.ErrResponseNotFound), "got: %v", err) require.True(t, errors.Is(err, native.ErrResponseNotFound), "got: %v", err)
resp := &transaction.OracleResponse{ resp := &transaction.OracleResponse{
ID: 13, ID: 12,
Code: transaction.Success, Code: transaction.Success,
Result: []byte{4, 8, 15, 16, 23, 42}, Result: []byte{4, 8, 15, 16, 23, 42},
} }
@ -173,7 +173,7 @@ func TestOracle_Request(t *testing.T) {
require.True(t, errors.Is(err, native.ErrRequestNotFound), "got: %v", err) require.True(t, errors.Is(err, native.ErrRequestNotFound), "got: %v", err)
// We need to ensure that callback is called thus, executing full script is necessary. // We need to ensure that callback is called thus, executing full script is necessary.
resp.ID = 1 resp.ID = 0
ic.VM.LoadScriptWithFlags(tx.Script, callflag.All) ic.VM.LoadScriptWithFlags(tx.Script, callflag.All)
require.NoError(t, ic.VM.Run()) require.NoError(t, ic.VM.Run())
@ -189,18 +189,18 @@ func TestOracle_Request(t *testing.T) {
require.Equal(t, resp.Result, arr[3].Value()) require.Equal(t, resp.Result, arr[3].Value())
// Check that processed request is removed during `postPersist`. // Check that processed request is removed during `postPersist`.
_, err = orc.GetRequestInternal(ic.DAO, 1) _, err = orc.GetRequestInternal(ic.DAO, 0)
require.NoError(t, err) require.NoError(t, err)
require.NoError(t, orc.PostPersist(ic)) require.NoError(t, orc.PostPersist(ic))
_, err = orc.GetRequestInternal(ic.DAO, 1) _, err = orc.GetRequestInternal(ic.DAO, 0)
require.Error(t, err) require.Error(t, err)
t.Run("ErrorOnFinish", func(t *testing.T) { t.Run("ErrorOnFinish", func(t *testing.T) {
const reqID = 2 const reqID = 1
putOracleRequest(t, cs.Hash, bc, "url", nil, "handle", []byte{1, 2}, gasForResponse) putOracleRequest(t, cs.Hash, bc, "url", nil, "handle", []byte{1, 2}, gasForResponse)
_, err := orc.GetRequestInternal(bc.dao, reqID) // ensure ID is 2 _, err := orc.GetRequestInternal(bc.dao, reqID) // ensure ID is 1
require.NoError(t, err) require.NoError(t, err)
tx = transaction.New(netmode.UnitTestNet, orc.GetOracleResponseScript(), 0) tx = transaction.New(netmode.UnitTestNet, orc.GetOracleResponseScript(), 0)

View file

@ -142,10 +142,10 @@ func TestStoragePrice(t *testing.T) {
t.Run("get, internal method", func(t *testing.T) { t.Run("get, internal method", func(t *testing.T) {
n := chain.contracts.Policy.GetStoragePriceInternal(chain.dao) n := chain.contracts.Policy.GetStoragePriceInternal(chain.dao)
require.Equal(t, int64(native.StoragePrice), n) require.Equal(t, int64(native.DefaultStoragePrice), n)
}) })
testGetSet(t, chain, chain.contracts.Policy.Hash, "StoragePrice", native.StoragePrice, 1, 10000000) testGetSet(t, chain, chain.contracts.Policy.Hash, "StoragePrice", native.DefaultStoragePrice, 1, 10000000)
} }
func TestBlockedAccounts(t *testing.T) { func TestBlockedAccounts(t *testing.T) {

View file

@ -165,26 +165,26 @@ func TestOracle(t *testing.T) {
t.Run("NormalRequest", func(t *testing.T) { t.Run("NormalRequest", func(t *testing.T) {
resp := &transaction.OracleResponse{ resp := &transaction.OracleResponse{
ID: 1, ID: 0,
Code: transaction.Success, Code: transaction.Success,
Result: []byte{1, 2, 3, 4}, Result: []byte{1, 2, 3, 4},
} }
req := checkResp(t, 1, resp) req := checkResp(t, 0, resp)
reqs := map[uint64]*state.OracleRequest{1: req} reqs := map[uint64]*state.OracleRequest{0: req}
orc2.ProcessRequestsInternal(reqs) orc2.ProcessRequestsInternal(reqs)
require.Equal(t, resp, m2[1].resp) require.Equal(t, resp, m2[0].resp)
require.Empty(t, ch2) require.Empty(t, ch2)
t.Run("InvalidSignature", func(t *testing.T) { t.Run("InvalidSignature", func(t *testing.T) {
orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[1].resp.ID, []byte{1, 2, 3}) orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[0].resp.ID, []byte{1, 2, 3})
require.Empty(t, ch1) require.Empty(t, ch1)
}) })
orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[1].resp.ID, m2[1].txSig) orc1.AddResponse(acc2.PrivateKey().PublicKey(), m2[0].resp.ID, m2[0].txSig)
checkEmitTx(t, ch1) checkEmitTx(t, ch1)
t.Run("FirstOtherThenMe", func(t *testing.T) { t.Run("FirstOtherThenMe", func(t *testing.T) {
const reqID = 2 const reqID = 1
resp := &transaction.OracleResponse{ resp := &transaction.OracleResponse{
ID: reqID, ID: reqID,
@ -203,58 +203,58 @@ func TestOracle(t *testing.T) {
}) })
t.Run("Invalid", func(t *testing.T) { t.Run("Invalid", func(t *testing.T) {
t.Run("Timeout", func(t *testing.T) { t.Run("Timeout", func(t *testing.T) {
checkResp(t, 3, &transaction.OracleResponse{ checkResp(t, 2, &transaction.OracleResponse{
ID: 3, ID: 2,
Code: transaction.Timeout, Code: transaction.Timeout,
}) })
}) })
t.Run("NotFound", func(t *testing.T) { t.Run("NotFound", func(t *testing.T) {
checkResp(t, 4, &transaction.OracleResponse{ checkResp(t, 3, &transaction.OracleResponse{
ID: 4, ID: 3,
Code: transaction.NotFound, Code: transaction.NotFound,
}) })
}) })
t.Run("Forbidden", func(t *testing.T) { t.Run("Forbidden", func(t *testing.T) {
checkResp(t, 4, &transaction.OracleResponse{
ID: 4,
Code: transaction.Forbidden,
})
})
t.Run("PrivateNetwork", func(t *testing.T) {
checkResp(t, 5, &transaction.OracleResponse{ checkResp(t, 5, &transaction.OracleResponse{
ID: 5, ID: 5,
Code: transaction.Forbidden, Code: transaction.Forbidden,
}) })
}) })
t.Run("PrivateNetwork", func(t *testing.T) { t.Run("Big", func(t *testing.T) {
checkResp(t, 6, &transaction.OracleResponse{ checkResp(t, 6, &transaction.OracleResponse{
ID: 6, ID: 6,
Code: transaction.Forbidden,
})
})
t.Run("Big", func(t *testing.T) {
checkResp(t, 7, &transaction.OracleResponse{
ID: 7,
Code: transaction.ResponseTooLarge, Code: transaction.ResponseTooLarge,
}) })
}) })
t.Run("MaxAllowedSmallGAS", func(t *testing.T) { t.Run("MaxAllowedSmallGAS", func(t *testing.T) {
checkResp(t, 8, &transaction.OracleResponse{ checkResp(t, 7, &transaction.OracleResponse{
ID: 8, ID: 7,
Code: transaction.InsufficientFunds, Code: transaction.InsufficientFunds,
}) })
}) })
}) })
t.Run("MaxAllowedEnoughGAS", func(t *testing.T) { t.Run("MaxAllowedEnoughGAS", func(t *testing.T) {
checkResp(t, 9, &transaction.OracleResponse{ checkResp(t, 8, &transaction.OracleResponse{
ID: 9, ID: 8,
Code: transaction.Success, Code: transaction.Success,
Result: make([]byte, transaction.MaxOracleResultSize), Result: make([]byte, transaction.MaxOracleResultSize),
}) })
}) })
t.Run("WithFilter", func(t *testing.T) { t.Run("WithFilter", func(t *testing.T) {
checkResp(t, 10, &transaction.OracleResponse{ checkResp(t, 9, &transaction.OracleResponse{
ID: 10, ID: 9,
Code: transaction.Success, Code: transaction.Success,
Result: []byte(`[2]`), Result: []byte(`[2]`),
}) })
t.Run("invalid response", func(t *testing.T) { t.Run("invalid response", func(t *testing.T) {
checkResp(t, 11, &transaction.OracleResponse{ checkResp(t, 10, &transaction.OracleResponse{
ID: 11, ID: 10,
Code: transaction.Error, Code: transaction.Error,
}) })
}) })

View file

@ -171,7 +171,7 @@ func (o *Oracle) Run() {
return return
case <-tick.C: case <-tick.C:
var reprocess []uint64 var reprocess []uint64
o.respMtx.RLock() o.respMtx.Lock()
o.removed = make(map[uint64]bool) o.removed = make(map[uint64]bool)
for id, incTx := range o.responses { for id, incTx := range o.responses {
incTx.RLock() incTx.RLock()

View file

@ -65,7 +65,7 @@ type VM struct {
state State state State
// callback to get interop price // callback to get interop price
getPrice func(*VM, opcode.Opcode, []byte) int64 getPrice func(opcode.Opcode, []byte) int64
istack *Stack // invocation stack. istack *Stack // invocation stack.
estack *Stack // execution stack. estack *Stack // execution stack.
@ -119,7 +119,7 @@ func (v *VM) newItemStack(n string) *Stack {
// SetPriceGetter registers the given PriceGetterFunc in v. // SetPriceGetter registers the given PriceGetterFunc in v.
// f accepts vm's Context, current instruction and instruction parameter. // f accepts vm's Context, current instruction and instruction parameter.
func (v *VM) SetPriceGetter(f func(*VM, opcode.Opcode, []byte) int64) { func (v *VM) SetPriceGetter(f func(opcode.Opcode, []byte) int64) {
v.getPrice = f v.getPrice = f
} }
@ -528,7 +528,7 @@ func (v *VM) execute(ctx *Context, op opcode.Opcode, parameter []byte) (err erro
}() }()
if v.getPrice != nil && ctx.ip < len(ctx.prog) { if v.getPrice != nil && ctx.ip < len(ctx.prog) {
v.gasConsumed += v.getPrice(v, op, parameter) v.gasConsumed += v.getPrice(op, parameter)
if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit { if v.GasLimit >= 0 && v.gasConsumed > v.GasLimit {
panic("gas limit is exceeded") panic("gas limit is exceeded")
} }

View file

@ -62,7 +62,7 @@ func TestVM_SetPriceGetter(t *testing.T) {
require.EqualValues(t, 0, v.GasConsumed()) require.EqualValues(t, 0, v.GasConsumed())
}) })
v.SetPriceGetter(func(_ *VM, op opcode.Opcode, p []byte) int64 { v.SetPriceGetter(func(op opcode.Opcode, p []byte) int64 {
if op == opcode.PUSH4 { if op == opcode.PUSH4 {
return 1 return 1
} else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) { } else if op == opcode.PUSHDATA1 && bytes.Equal(p, []byte{0xCA, 0xFE}) {