forked from TrueCloudLab/frostfs-contract
[#150] container: allow only alphabet calls in Put
For notary-enabled environment we expect `put` to be signed by alphabet. Also group notary-disabled logic inside a single if and add tests for balance checks. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
5c58093a75
commit
a7601334f7
3 changed files with 53 additions and 35 deletions
|
@ -173,37 +173,24 @@ func PutNamed(container []byte, signature interop.Signature,
|
||||||
needRegister = checkNiceNameAvailable(nnsContractAddr, domain)
|
needRegister = checkNiceNameAvailable(nnsContractAddr, domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
var ( // for invocation collection without notary
|
alphabet := common.AlphabetNodes()
|
||||||
alphabet = common.AlphabetNodes()
|
|
||||||
nodeKey []byte
|
|
||||||
alphabetCall bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if notaryDisabled {
|
|
||||||
nodeKey = common.InnerRingInvoker(alphabet)
|
|
||||||
alphabetCall = len(nodeKey) != 0
|
|
||||||
} else {
|
|
||||||
multiaddr := common.AlphabetAddress()
|
|
||||||
alphabetCall = runtime.CheckWitness(multiaddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
from := common.WalletToScriptHash(ownerID)
|
from := common.WalletToScriptHash(ownerID)
|
||||||
netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160)
|
netmapContractAddr := storage.Get(ctx, netmapContractKey).(interop.Hash160)
|
||||||
balanceContractAddr := storage.Get(ctx, balanceContractKey).(interop.Hash160)
|
balanceContractAddr := storage.Get(ctx, balanceContractKey).(interop.Hash160)
|
||||||
containerFee := contract.Call(netmapContractAddr, "config", contract.ReadOnly, containerFeeKey).(int)
|
containerFee := contract.Call(netmapContractAddr, "config", contract.ReadOnly, containerFeeKey).(int)
|
||||||
balance := contract.Call(balanceContractAddr, "balanceOf", contract.ReadOnly, from).(int)
|
balance := contract.Call(balanceContractAddr, "balanceOf", contract.ReadOnly, from).(int)
|
||||||
details := common.ContainerFeeTransferDetails(containerID)
|
|
||||||
|
|
||||||
if !alphabetCall {
|
|
||||||
if balance < containerFee*len(alphabet) {
|
if balance < containerFee*len(alphabet) {
|
||||||
panic("insufficient balance to create container")
|
panic("insufficient balance to create container")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if notaryDisabled {
|
||||||
|
nodeKey := common.InnerRingInvoker(alphabet)
|
||||||
|
if len(nodeKey) == 0 {
|
||||||
runtime.Notify("containerPut", container, signature, publicKey, token)
|
runtime.Notify("containerPut", container, signature, publicKey, token)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// todo: check if new container with unique container id
|
|
||||||
|
|
||||||
if notaryDisabled {
|
|
||||||
threshold := len(alphabet)*2/3 + 1
|
threshold := len(alphabet)*2/3 + 1
|
||||||
id := common.InvokeID([]interface{}{container, signature, publicKey}, []byte("put"))
|
id := common.InvokeID([]interface{}{container, signature, publicKey}, []byte("put"))
|
||||||
|
|
||||||
|
@ -213,7 +200,15 @@ func PutNamed(container []byte, signature interop.Signature,
|
||||||
}
|
}
|
||||||
|
|
||||||
common.RemoveVotes(ctx, id)
|
common.RemoveVotes(ctx, id)
|
||||||
|
} else {
|
||||||
|
multiaddr := common.AlphabetAddress()
|
||||||
|
if !runtime.CheckWitness(multiaddr) {
|
||||||
|
panic("put: alphabet witness check failed")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
// todo: check if new container with unique container id
|
||||||
|
|
||||||
|
details := common.ContainerFeeTransferDetails(containerID)
|
||||||
|
|
||||||
for i := 0; i < len(alphabet); i++ {
|
for i := 0; i < len(alphabet); i++ {
|
||||||
node := alphabet[i]
|
node := alphabet[i]
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/core"
|
"github.com/nspcc-dev/neo-go/pkg/core"
|
||||||
"github.com/nspcc-dev/neo-go/pkg/util"
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
const balancePath = "../balance"
|
const balancePath = "../balance"
|
||||||
|
@ -16,3 +17,8 @@ func deployBalanceContract(t *testing.T, bc *core.Blockchain, addrNetmap, addrCo
|
||||||
args[2] = addrContainer
|
args[2] = addrContainer
|
||||||
return DeployContract(t, bc, balancePath, args)
|
return DeployContract(t, bc, balancePath, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func balanceMint(t *testing.T, bc *core.Blockchain, acc *wallet.Account, h util.Uint160, amount int64, details []byte) {
|
||||||
|
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "mint", acc.Contract.ScriptHash(), amount, details)
|
||||||
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@ import (
|
||||||
|
|
||||||
const containerPath = "../container"
|
const containerPath = "../container"
|
||||||
|
|
||||||
|
const containerFee = 0_0100_0000
|
||||||
|
|
||||||
func deployContainerContract(t *testing.T, bc *core.Blockchain, addrNetmap, addrBalance, addrNNS util.Uint160) util.Uint160 {
|
func deployContainerContract(t *testing.T, bc *core.Blockchain, addrNetmap, addrBalance, addrNNS util.Uint160) util.Uint160 {
|
||||||
args := make([]interface{}, 6)
|
args := make([]interface{}, 6)
|
||||||
args[0] = int64(0)
|
args[0] = int64(0)
|
||||||
|
@ -26,7 +28,7 @@ func deployContainerContract(t *testing.T, bc *core.Blockchain, addrNetmap, addr
|
||||||
return DeployContract(t, bc, containerPath, args)
|
return DeployContract(t, bc, containerPath, args)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareContainerContract(t *testing.T, bc *core.Blockchain) util.Uint160 {
|
func prepareContainerContract(t *testing.T, bc *core.Blockchain) (util.Uint160, util.Uint160) {
|
||||||
addrNNS := DeployContract(t, bc, nnsPath, nil)
|
addrNNS := DeployContract(t, bc, nnsPath, nil)
|
||||||
|
|
||||||
ctrNetmap, err := ContractInfo(CommitteeAcc.Contract.ScriptHash(), netmapPath)
|
ctrNetmap, err := ContractInfo(CommitteeAcc.Contract.ScriptHash(), netmapPath)
|
||||||
|
@ -38,9 +40,9 @@ func prepareContainerContract(t *testing.T, bc *core.Blockchain) util.Uint160 {
|
||||||
ctrContainer, err := ContractInfo(CommitteeAcc.Contract.ScriptHash(), containerPath)
|
ctrContainer, err := ContractInfo(CommitteeAcc.Contract.ScriptHash(), containerPath)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
deployNetmapContract(t, bc, ctrBalance.Hash, ctrContainer.Hash, "ContainerFee", []byte{})
|
deployNetmapContract(t, bc, ctrBalance.Hash, ctrContainer.Hash, "ContainerFee", int64(containerFee))
|
||||||
deployBalanceContract(t, bc, ctrNetmap.Hash, ctrContainer.Hash)
|
balHash := deployBalanceContract(t, bc, ctrNetmap.Hash, ctrContainer.Hash)
|
||||||
return deployContainerContract(t, bc, ctrNetmap.Hash, ctrBalance.Hash, addrNNS)
|
return deployContainerContract(t, bc, ctrNetmap.Hash, ctrBalance.Hash, addrNNS), balHash
|
||||||
}
|
}
|
||||||
|
|
||||||
func setContainerOwner(c []byte, owner *wallet.Account) {
|
func setContainerOwner(c []byte, owner *wallet.Account) {
|
||||||
|
@ -49,7 +51,7 @@ func setContainerOwner(c []byte, owner *wallet.Account) {
|
||||||
|
|
||||||
func TestContainerPut(t *testing.T) {
|
func TestContainerPut(t *testing.T) {
|
||||||
bc := NewChain(t)
|
bc := NewChain(t)
|
||||||
h := prepareContainerContract(t, bc)
|
h, balanceHash := prepareContainerContract(t, bc)
|
||||||
|
|
||||||
acc := NewAccount(t, bc)
|
acc := NewAccount(t, bc)
|
||||||
dummySig := make([]byte, 64)
|
dummySig := make([]byte, 64)
|
||||||
|
@ -59,17 +61,30 @@ func TestContainerPut(t *testing.T) {
|
||||||
setContainerOwner(container, acc)
|
setContainerOwner(container, acc)
|
||||||
containerID := sha256.Sum256(container)
|
containerID := sha256.Sum256(container)
|
||||||
|
|
||||||
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", container, dummySig, dummyPub, dummyToken)
|
putArgs := []interface{}{container, dummySig, dummyPub, dummyToken}
|
||||||
|
tx := PrepareInvoke(t, bc, CommitteeAcc, h, "put", putArgs...)
|
||||||
|
AddBlock(t, bc, tx)
|
||||||
|
CheckFault(t, bc, tx.Hash(), "insufficient balance to create container")
|
||||||
|
|
||||||
|
balanceMint(t, bc, acc, balanceHash, containerFee*1, []byte{})
|
||||||
|
|
||||||
|
tx = PrepareInvoke(t, bc, acc, h, "put", putArgs...)
|
||||||
|
AddBlock(t, bc, tx)
|
||||||
|
CheckFault(t, bc, tx.Hash(), "alphabet witness check failed")
|
||||||
|
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "put", putArgs...)
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
t.Run("with nice names", func(t *testing.T) {
|
t.Run("with nice names", func(t *testing.T) {
|
||||||
nnsHash := contracts[nnsPath].Hash
|
nnsHash := contracts[nnsPath].Hash
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "putNamed",
|
balanceMint(t, bc, acc, balanceHash, containerFee*1, []byte{})
|
||||||
container, dummySig, dummyPub, dummyToken, "mycnt", "")
|
|
||||||
|
putArgs := []interface{}{container, dummySig, dummyPub, dummyToken, "mycnt", ""}
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "putNamed", putArgs...)
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, nnsHash, "resolve", "mycnt.neofs", int64(nns.TXT))
|
tx = PrepareInvoke(t, bc, acc, nnsHash, "resolve", "mycnt.neofs", int64(nns.TXT))
|
||||||
CheckTestInvoke(t, bc, tx, stackitem.NewArray([]stackitem.Item{
|
CheckTestInvoke(t, bc, tx, stackitem.NewArray([]stackitem.Item{
|
||||||
stackitem.NewByteArray([]byte(base58.Encode(containerID[:]))),
|
stackitem.NewByteArray([]byte(base58.Encode(containerID[:]))),
|
||||||
}))
|
}))
|
||||||
|
@ -84,13 +99,15 @@ func TestContainerPut(t *testing.T) {
|
||||||
container[len(container)-1] = 10
|
container[len(container)-1] = 10
|
||||||
containerID = sha256.Sum256(container)
|
containerID = sha256.Sum256(container)
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, nnsHash, "register",
|
tx = PrepareInvoke(t, bc, CommitteeAcc, nnsHash, "register",
|
||||||
"second.neofs", acc.Contract.ScriptHash(),
|
"second.neofs", CommitteeAcc.Contract.ScriptHash(),
|
||||||
"whateveriwant@world.com", int64(0), int64(0), int64(0), int64(0))
|
"whateveriwant@world.com", int64(0), int64(0), int64(0), int64(0))
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, []*wallet.Account{CommitteeAcc, acc}, h, "putNamed",
|
balanceMint(t, bc, acc, balanceHash, containerFee*1, []byte{})
|
||||||
container, dummySig, dummyPub, dummyToken, "second", "neofs")
|
|
||||||
|
putArgs := []interface{}{container, dummySig, dummyPub, dummyToken, "second", "neofs"}
|
||||||
|
tx = PrepareInvoke(t, bc, CommitteeAcc, h, "putNamed", putArgs...)
|
||||||
AddBlockCheckHalt(t, bc, tx)
|
AddBlockCheckHalt(t, bc, tx)
|
||||||
|
|
||||||
tx = PrepareInvoke(t, bc, CommitteeAcc, nnsHash, "resolve", "second.neofs", int64(nns.TXT))
|
tx = PrepareInvoke(t, bc, CommitteeAcc, nnsHash, "resolve", "second.neofs", int64(nns.TXT))
|
||||||
|
|
Loading…
Reference in a new issue