Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core v2 factories #162

Open
wants to merge 7 commits into
base: feat/v2
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 124 additions & 0 deletions coreV2/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package coreV2

import (
"encoding/hex"
"fmt"
"strings"

"github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
)

const (
CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l"
)

type address struct {
publicKey []byte
hrp string
}

type AddressGetter interface {
GetPublicKey() []byte
GetHRP() string
}

type Address interface {
AddressGetter
ToHex() string
ToBech32() (string, error)
IsSmartContract() bool
}

func NewAddress(publicKey []byte, hrp string) (Address, error) {
if len(publicKey) != AddressBytesLen {
return nil, pubkeyConverter.ErrInvalidAddressLength
}

return &address{publicKey: publicKey, hrp: hrp}, nil
}

func NewAddressFromBech32(value string) (Address, error) {
hrp, err := determineHRP(value)
if err != nil {
return nil, fmt.Errorf("failed to determine HRP: %v", err)
}
converter, err := pubkeyConverter.NewBech32PubkeyConverter(AddressBytesLen, hrp)
if err != nil {
return nil, fmt.Errorf("failed to create bech32 converter: %v", err)
}

decode, err := converter.Decode(value)
if err != nil {
return nil, fmt.Errorf("failed to decode %q to bech32: %v", decode, err)
}

return &address{publicKey: decode, hrp: hrp}, nil
}

func NewAddressFromHex(value, hrp string) (Address, error) {
converter, err := pubkeyConverter.NewHexPubkeyConverter(AddressBytesLen)
if err != nil {
return nil, fmt.Errorf("failed to create hex converter: %v", err)
}

publicKey, err := converter.Decode(value)
if err != nil {
return nil, fmt.Errorf("failed to decode %q to hex: %v", value, err)
}

return &address{publicKey: publicKey, hrp: hrp}, nil
}

func (a *address) GetPublicKey() []byte {
return a.publicKey
}

func (a *address) GetHRP() string {
return a.hrp
}

func (a *address) ToHex() string {
return hex.EncodeToString(a.publicKey)
}

func (a *address) ToBech32() (string, error) {
converter, err := pubkeyConverter.NewBech32PubkeyConverter(AddressBytesLen, a.hrp)
if err != nil {
return "", fmt.Errorf("failed to create bech32 converter: %v", err)
}
bech32, err := converter.Encode(a.publicKey)
if err != nil {
return "", fmt.Errorf("failed to convert address to bech32: %v", err)
}

return bech32, nil
}

func (a *address) IsSmartContract() bool {
return strings.HasPrefix(a.ToHex(), ScHexPubKeyPrefix)
}

func determineHRP(bech string) (string, error) {
if len(bech) < 32 || len(bech) > 125 {
return "", fmt.Errorf("address provided %q doesn't have the correct length", bech)
}

if strings.ToLower(bech) != bech && strings.ToUpper(bech) != bech {
return "", fmt.Errorf("address provided %q has both uppercase and lowercase characters", bech)
}

bech = strings.ToLower(bech)
pos := strings.Index(bech, "1")

if pos < 1 || pos+7 > len(bech) || len(bech) > 90 {
return "", fmt.Errorf("address provided %q is invalid", bech)
}

for _, x := range bech[pos+1:] {
if !strings.Contains(CHARSET, string(x)) {
return "", fmt.Errorf("address provided %q is invalid", bech)
}
}

return bech[:pos], nil
}
38 changes: 38 additions & 0 deletions coreV2/address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package coreV2

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestNewAddressFromBech32(t *testing.T) {
value := "erd104ct3knz45kt2s7ap93haqz3nrahzgf35zjpgq28fl99qrlepd6sqx6nf4"

a, err := NewAddressFromBech32(value)
require.NoError(t, err)

a2, err := NewAddressFromHex(a.ToHex(), "erd")
require.NoError(t, err)

require.Equal(t, a, a2)
}

func TestAddressWithCustomHRP(t *testing.T) {
a, err := NewAddressFromHex("0139472eff6886771a982f3083da5d421f24c29181e63888228dc81ca60d69e1", "test")
require.NoError(t, err, "failed to create address from hex")

bech32, err := a.ToBech32()
require.NoError(t, err, "failed to retrieve bech32 from address")
a1, err := NewAddressFromBech32(bech32)
require.NoError(t, err, "failed to create address from bech32")

a2, err := NewAddressFromHex(a.ToHex(), "test")
require.NoError(t, err)

require.Equal(t, a, a1, a2)
}

func TestAddress_IsSmartContract(t *testing.T) {

}
83 changes: 83 additions & 0 deletions coreV2/codeMetadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package coreV2

import (
"encoding/hex"
)

const (
Upgradeable byte = 1
Reserved2 byte = 2
Readable byte = 4
Reserved1 byte = 1
Payable byte = 2
PayableByContract = 4
)

type Option func(metadata *codeMetadata)

type codeMetadata struct {
Upgradeable bool
Readable bool
Payable bool
PayableByContract bool
}

func NewCodeMetadata(opts ...Option) *codeMetadata {
cm := codeMetadata{Upgradeable: true, Readable: true, Payable: false, PayableByContract: false}

for _, opt := range opts {
opt(&cm)
}

return &cm
}

func WithUpgradeable(upgradeable bool) func(metadata *codeMetadata) {
return func(metadata *codeMetadata) {
metadata.Upgradeable = upgradeable
}
}

func WithReadable(readable bool) func(metadata *codeMetadata) {
return func(metadata *codeMetadata) {
metadata.Readable = readable
}
}

func WithPayable(payable bool) func(metadata *codeMetadata) {
return func(metadata *codeMetadata) {
metadata.Payable = payable
}
}

func WithPayableByContract(payableByContract bool) func(metadata *codeMetadata) {
return func(metadata *codeMetadata) {
metadata.PayableByContract = payableByContract
}
}

func (cm *codeMetadata) serialize() []byte {
data := []byte{0, 0}

if cm.Upgradeable {
data[0] |= Upgradeable
}

if cm.Readable {
data[0] |= Readable
}

if cm.Payable {
data[1] |= Payable
}

if cm.PayableByContract {
data[1] |= PayableByContract
}

return data
}

func (cm *codeMetadata) String() string {
return hex.EncodeToString(cm.serialize())
}
30 changes: 30 additions & 0 deletions coreV2/constants.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package coreV2

import (
"github.com/multiversx/mx-chain-core-go/core/pubkeyConverter"
)

const (
// AddressBytesLen represents the number of bytes of an address
AddressBytesLen = 32

// MinAllowedDeltaToFinal is the minimum value between nonces allowed when checking finality on a shard
MinAllowedDeltaToFinal = 1

// WebServerOffString represents the constant used to switch off the web server
WebServerOffString = "off"

// DefaultAddressPrefix is the default hrp of MultiversX/Elrond
DefaultAddressPrefix = "erd"

ScHexPubKeyPrefix = "0000000000000000"
)

var (
// AddressPublicKeyConverter represents the default address public key converter
AddressPublicKeyConverter, _ = pubkeyConverter.NewBech32PubkeyConverter(AddressBytesLen, DefaultAddressPrefix)
)

func GetVMTypeWASMVM() []byte {
return []byte{0x05, 0x00}
}
Loading
Loading