diff --git a/container/config.yml b/container/config.yml index 9778ed3..df98605 100644 --- a/container/config.yml +++ b/container/config.yml @@ -18,6 +18,7 @@ permissions: - "register" - "transferX" - "update" + - "setAdmin" events: - name: PutSuccess diff --git a/container/container_contract.go b/container/container_contract.go index c6b0420..a4f0ebf 100644 --- a/container/container_contract.go +++ b/container/container_contract.go @@ -565,6 +565,21 @@ func NewEpoch(epochNum int) { cleanupContainers(ctx, epochNum) } +// SetAdmin sets admin for root container domain. +func SetAdmin(admin interop.Hash160) { + ctx := storage.GetReadOnlyContext() + + if !runtime.CheckWitness(common.CommitteeAddress()) { + panic("only committee can set admin") + } + + addrNNS := storage.Get(ctx, nnsContractKey).(interop.Hash160) + rootContainerDomain := storage.Get(ctx, nnsRootKey).(string) + + contract.Call(addrNNS, "setAdmin", contract.All, + rootContainerDomain, admin) +} + // StartContainerEstimation method produces StartEstimation notification. // It can be invoked only by Alphabet nodes of the Inner Ring. func StartContainerEstimation(epoch int) { diff --git a/rpcclient/container/client.go b/rpcclient/container/client.go index 216a912..85b428a 100644 --- a/rpcclient/container/client.go +++ b/rpcclient/container/client.go @@ -270,6 +270,28 @@ func (c *Contract) PutNamedUnsigned(container []byte, signature []byte, publicKe return c.actor.MakeUnsignedCall(c.hash, "putNamed", nil, container, signature, publicKey, token, name, zone) } +// SetAdmin creates a transaction invoking `setAdmin` method of the contract. +// This transaction is signed and immediately sent to the network. +// The values returned are its hash, ValidUntilBlock value and error if any. +func (c *Contract) SetAdmin(admin util.Uint160) (util.Uint256, uint32, error) { + return c.actor.SendCall(c.hash, "setAdmin", admin) +} + +// SetAdminTransaction creates a transaction invoking `setAdmin` method of the contract. +// This transaction is signed, but not sent to the network, instead it's +// returned to the caller. +func (c *Contract) SetAdminTransaction(admin util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeCall(c.hash, "setAdmin", admin) +} + +// SetAdminUnsigned creates a transaction invoking `setAdmin` method of the contract. +// This transaction is not signed, it's simply returned to the caller. +// Any fields of it that do not affect fees can be changed (ValidUntilBlock, +// Nonce), fee values (NetworkFee, SystemFee) can be increased as well. +func (c *Contract) SetAdminUnsigned(admin util.Uint160) (*transaction.Transaction, error) { + return c.actor.MakeUnsignedCall(c.hash, "setAdmin", nil, admin) +} + // SetEACL creates a transaction invoking `setEACL` method of the contract. // This transaction is signed and immediately sent to the network. // The values returned are its hash, ValidUntilBlock value and error if any. diff --git a/tests/container_test.go b/tests/container_test.go index f1cd07d..d57003f 100644 --- a/tests/container_test.go +++ b/tests/container_test.go @@ -241,6 +241,16 @@ func TestContainerPut(t *testing.T) { }) }) + t.Run("test setAdmin", func(t *testing.T) { + ctrNNS := neotest.CompileFile(t, c.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) + nnsInv := c.NewInvoker(ctrNNS.Hash, acc) + containerInv := c.WithSigners(c.Committee, acc) + + nnsInv.InvokeFail(t, "not witnessed by admin", "addRecord", "frostfs", int64(nns.TXT), nns.Cnametgt+"=animals") + containerInv.Invoke(t, stackitem.Null{}, "setAdmin", acc.ScriptHash()) + nnsInv.Invoke(t, stackitem.Null{}, "addRecord", "frostfs", int64(nns.TXT), nns.Cnametgt+"=animals") + }) + t.Run("create global domain", func(t *testing.T) { ctrNNS := neotest.CompileFile(t, c.CommitteeHash, nnsPath, path.Join(nnsPath, "config.yml")) nnsHash := ctrNNS.Hash