Skip to content

Commit

Permalink
[MULTISIG] Storing Alias definitions in Smart Contract state
Browse files Browse the repository at this point in the history
  • Loading branch information
Paweł Nowosielski committed Apr 13, 2023
1 parent 656452d commit 1db886b
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 5 deletions.
17 changes: 17 additions & 0 deletions contracts/camino_smart_contracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package contracts

import (
"math/big"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

func NextSlot(addr common.Hash) common.Hash {
bigAddr := new(big.Int).Add(addr.Big(), common.Big1)
return common.BigToHash(bigAddr)
}

func EntryAddress(address common.Address, slot int64) common.Hash {
return crypto.Keccak256Hash(address.Hash().Bytes(), common.BigToHash(big.NewInt(slot)).Bytes())
}
25 changes: 24 additions & 1 deletion contracts/camino_smart_contracts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/ava-labs/coreth/accounts/abi/bind/backends"
"github.com/ava-labs/coreth/accounts/keystore"
"github.com/ava-labs/coreth/consensus/dummy"
admin "github.com/ava-labs/coreth/contracts/build_contracts/admin/src"
"github.com/ava-labs/coreth/core"
"github.com/ava-labs/coreth/core/rawdb"
"github.com/ava-labs/coreth/core/state"
Expand All @@ -32,7 +33,7 @@ import (
"github.com/ava-labs/coreth/params"
"github.com/ava-labs/coreth/vmerrs"

admin "github.com/ava-labs/coreth/contracts/build_contracts/admin/src"
"github.com/stretchr/testify/require"
)

var (
Expand Down Expand Up @@ -687,3 +688,25 @@ func addAndVerifyRoles(t *testing.T, adminSession admin.BuildSession, sim *backe

return roles
}

func TestStorageSlotIndices(t *testing.T) {
// See article about storing solidity structures https://c4t.atlassian.net/wiki/spaces/TECH/pages/315228161/Extending+Multisig+support+to+other+chains+X+C
const (
expectedAliasThresholdSlot = "0x02d8eabfe500216f0da458b4ce6732047b68f7e037b3e2d7313765a12e1ff7fc"
expectedAliasCGroupArrayLengthSlot = "0x02d8eabfe500216f0da458b4ce6732047b68f7e037b3e2d7313765a12e1ff7fd"
expectedAliasCGroupArraySlot = "0xba536a6eed5d97c805d767eb1aaffd73a6446dbca7494685f2c6f3bdc1fd2777"
)
var (
aliasAdddress = common.HexToAddress("0x010000000000000000000000000000000000000e")
contractMappingSlot = int64(0)
)

aliasThresholdSlot := EntryAddress(aliasAdddress, contractMappingSlot)
require.Equal(t, expectedAliasThresholdSlot, aliasThresholdSlot.String())

aliasArrayLenSlot := NextSlot(aliasThresholdSlot)
require.Equal(t, expectedAliasCGroupArrayLengthSlot, aliasArrayLenSlot.String())

aliasArrauSlot := crypto.Keccak256Hash(aliasArrayLenSlot.Bytes())
require.Equal(t, expectedAliasCGroupArraySlot, aliasArrauSlot.String())
}
45 changes: 41 additions & 4 deletions plugin/evm/import_tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package evm
import (
"errors"
"fmt"
"github.com/ava-labs/coreth/contracts"
"math/big"

"github.com/ava-labs/coreth/core"
Expand All @@ -20,18 +21,22 @@ import (
"github.com/ava-labs/avalanchego/utils/math"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/avalanchego/vms/components/avax"
"github.com/ava-labs/avalanchego/vms/components/multisig"
"github.com/ava-labs/avalanchego/vms/components/verify"
"github.com/ava-labs/avalanchego/vms/secp256k1fx"

"github.com/ethereum/go-ethereum/common"
ethCrypto "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/log"
)

var (
_ UnsignedAtomicTx = &UnsignedImportTx{}
_ secp256k1fx.UnsignedTx = &UnsignedImportTx{}
errImportNonAVAXInputBanff = errors.New("import input cannot contain non-AVAX in Banff")
errImportNonAVAXOutputBanff = errors.New("import output cannot contain non-AVAX in Banff")
_ UnsignedAtomicTx = &UnsignedImportTx{}
_ secp256k1fx.UnsignedTx = &UnsignedImportTx{}
errImportNonAVAXInputBanff = errors.New("import input cannot contain non-AVAX in Banff")
errImportNonAVAXOutputBanff = errors.New("import output cannot contain non-AVAX in Banff")
multisigAliasContractAddress = common.HexToAddress("0x010000000000000000000000000000000000000e")
multisigAliasMappingSlot = int64(0)
)

// UnsignedImportTx is an unsigned ImportTx
Expand All @@ -47,6 +52,8 @@ type UnsignedImportTx struct {
ImportedInputs []*avax.TransferableInput `serialize:"true" json:"importedInputs"`
// Outputs
Outs []EVMOutput `serialize:"true" json:"outputs"`
// MultisigAliases are filled on SemanticVerify where SharedMemory data is fetched and are used in EVMStateTransfer
MultisigAliases []*multisig.AliasWithNonce `serialize:"false"`
}

// InputUTXOs returns the UTXOIDs of the imported funds
Expand Down Expand Up @@ -301,6 +308,13 @@ func (utx *UnsignedImportTx) SemanticVerify(
}
}

utx.MultisigAliases = make([]*multisig.AliasWithNonce, len(*aliasSet))
i := 0
for _, alias := range *aliasSet {
utx.MultisigAliases[i] = alias
i++
}

return vm.conflicts(utx.InputUTXOs(), parent)
}

Expand Down Expand Up @@ -487,5 +501,28 @@ func (utx *UnsignedImportTx) EVMStateTransfer(ctx *snow.Context, state *state.St
state.AddBalanceMultiCoin(to.Address, common.Hash(to.AssetID), amount)
}
}
for _, alias := range utx.MultisigAliases {
setAliasInState(state, alias)
}
return nil
}

func setAliasInState(state *state.StateDB, alias *multisig.AliasWithNonce) {
aliasIDAddress := common.BytesToAddress(alias.ID.Bytes())
owners := alias.Owners.(*secp256k1fx.OutputOwners)

aliasThresholdSlot := contracts.EntryAddress(aliasIDAddress, multisigAliasMappingSlot)
aliasThresholdBig := big.NewInt(int64(owners.Threshold))
state.SetState(multisigAliasContractAddress, aliasThresholdSlot, common.BigToHash(aliasThresholdBig))

aliasArrayLengthSlot := contracts.NextSlot(aliasThresholdSlot)
aliasArrayLengthBig := big.NewInt(int64(len(owners.Addrs)))
state.SetState(multisigAliasContractAddress, aliasArrayLengthSlot, common.BigToHash(aliasArrayLengthBig))

aliasArrayElemSlot := ethCrypto.Keccak256Hash(aliasArrayLengthSlot.Bytes())
for _, owner := range owners.Addrs {
ownerAddress := common.BytesToAddress(owner.Bytes())
state.SetState(multisigAliasContractAddress, aliasArrayElemSlot, ownerAddress.Hash())
aliasArrayElemSlot = contracts.NextSlot(aliasArrayElemSlot)
}
}

0 comments on commit 1db886b

Please sign in to comment.