mirror of https://github.com/certusone/wasmd.git
78 lines
3.0 KiB
Go
78 lines
3.0 KiB
Go
package keeper
|
|
|
|
import (
|
|
"context"
|
|
"encoding/binary"
|
|
"fmt"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/cosmos/cosmos-sdk/types/address"
|
|
|
|
"github.com/CosmWasm/wasmd/x/wasm/types"
|
|
)
|
|
|
|
// AddressGenerator abstract address generator to be used for a single contract address
|
|
type AddressGenerator func(ctx context.Context, codeID uint64, checksum []byte) sdk.AccAddress
|
|
|
|
// ClassicAddressGenerator generates a contract address using codeID and instanceID sequence
|
|
func (k Keeper) ClassicAddressGenerator() AddressGenerator {
|
|
return func(ctx context.Context, codeID uint64, _ []byte) sdk.AccAddress {
|
|
instanceID := k.mustAutoIncrementID(ctx, types.KeySequenceInstanceID)
|
|
return BuildContractAddressClassic(codeID, instanceID)
|
|
}
|
|
}
|
|
|
|
// PredictableAddressGenerator generates a predictable contract address
|
|
func PredictableAddressGenerator(creator sdk.AccAddress, salt, msg []byte, fixMsg bool) AddressGenerator {
|
|
return func(_ context.Context, _ uint64, checksum []byte) sdk.AccAddress {
|
|
if !fixMsg { // clear msg to not be included in the address generation
|
|
msg = []byte{}
|
|
}
|
|
return BuildContractAddressPredictable(checksum, creator, salt, msg)
|
|
}
|
|
}
|
|
|
|
// BuildContractAddressClassic builds an address for a contract.
|
|
func BuildContractAddressClassic(codeID, instanceID uint64) sdk.AccAddress {
|
|
contractID := make([]byte, 16)
|
|
binary.BigEndian.PutUint64(contractID[:8], codeID)
|
|
binary.BigEndian.PutUint64(contractID[8:], instanceID)
|
|
return address.Module(types.ModuleName, contractID)[:types.ContractAddrLen]
|
|
}
|
|
|
|
// BuildContractAddressPredictable generates a contract address for the wasm module with len = types.ContractAddrLen using the
|
|
// Cosmos SDK address.Module function.
|
|
// Internally a key is built containing:
|
|
// (len(checksum) | checksum | len(sender_address) | sender_address | len(salt) | salt| len(initMsg) | initMsg).
|
|
//
|
|
// All method parameter values must be valid and not nil.
|
|
func BuildContractAddressPredictable(checksum []byte, creator sdk.AccAddress, salt, initMsg types.RawContractMessage) sdk.AccAddress {
|
|
if len(checksum) != 32 {
|
|
panic("invalid checksum")
|
|
}
|
|
if err := sdk.VerifyAddressFormat(creator); err != nil {
|
|
panic(fmt.Sprintf("creator: %s", err))
|
|
}
|
|
if err := types.ValidateSalt(salt); err != nil {
|
|
panic(fmt.Sprintf("salt: %s", err))
|
|
}
|
|
if err := initMsg.ValidateBasic(); len(initMsg) != 0 && err != nil {
|
|
panic(fmt.Sprintf("initMsg: %s", err))
|
|
}
|
|
checksum = UInt64LengthPrefix(checksum)
|
|
creator = UInt64LengthPrefix(creator)
|
|
salt = UInt64LengthPrefix(salt)
|
|
initMsg = UInt64LengthPrefix(initMsg)
|
|
key := make([]byte, len(checksum)+len(creator)+len(salt)+len(initMsg))
|
|
copy(key[0:], checksum)
|
|
copy(key[len(checksum):], creator)
|
|
copy(key[len(checksum)+len(creator):], salt)
|
|
copy(key[len(checksum)+len(creator)+len(salt):], initMsg)
|
|
return address.Module(types.ModuleName, key)[:types.ContractAddrLen]
|
|
}
|
|
|
|
// UInt64LengthPrefix prepend big endian encoded byte length
|
|
func UInt64LengthPrefix(bz []byte) []byte {
|
|
return append(sdk.Uint64ToBigEndian(uint64(len(bz))), bz...)
|
|
}
|