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

[chain] Address Refactor #571

Merged
merged 98 commits into from
Nov 6, 2023
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
98 commits
Select commit Hold shift + click to select a range
1c298f0
break apart useful utils
patrick-ogrady Oct 17, 2023
6297ab4
work on generalizing address
patrick-ogrady Oct 17, 2023
6765794
test invalid checksum
patrick-ogrady Oct 17, 2023
92b1a83
add tests for bech32 encoding
patrick-ogrady Oct 17, 2023
0fb3887
add check for invalid checksum
patrick-ogrady Oct 17, 2023
0c932e7
add utils tests
patrick-ogrady Oct 18, 2023
02964a2
remove shared utilities from crypto packages
patrick-ogrady Oct 18, 2023
bc7ba8b
remove HRP error from crypto
patrick-ogrady Oct 18, 2023
67dd621
update secp256r1 auth
patrick-ogrady Oct 18, 2023
75e93ad
work on refactoring packing
patrick-ogrady Oct 18, 2023
a5fff3f
generalize storage + revert address refactor
patrick-ogrady Oct 18, 2023
037a1b4
update ed25519 storage
patrick-ogrady Oct 18, 2023
2af9774
unmarshaling works
patrick-ogrady Oct 18, 2023
fe6cccc
update transfer action
patrick-ogrady Oct 18, 2023
cf0df18
add to auth registry
patrick-ogrady Oct 18, 2023
b7a2974
remove panic
patrick-ogrady Oct 18, 2023
83bd951
vm compiles
patrick-ogrady Oct 18, 2023
1873488
integration compiles
patrick-ogrady Oct 18, 2023
dc46eac
add TODO to fix bug
patrick-ogrady Oct 18, 2023
0d141d0
add more TODOs
patrick-ogrady Oct 18, 2023
173793b
fix circular dependency
patrick-ogrady Oct 18, 2023
c7d24ef
morpheus compiles
patrick-ogrady Oct 18, 2023
e808d6e
integration passing
patrick-ogrady Oct 18, 2023
6c904cd
sending between secp256r1 and ed25519
patrick-ogrady Oct 18, 2023
3352f34
cleanup auth/helpers
patrick-ogrady Oct 18, 2023
1373c73
remove unnecessary TODOs
patrick-ogrady Oct 19, 2023
1808927
use address terminology byte representation
patrick-ogrady Oct 19, 2023
68fe62f
remove unnecessary helper
patrick-ogrady Oct 19, 2023
ac2a454
remove balance key logging
patrick-ogrady Oct 19, 2023
0773913
remove ShortBytes from crypto
patrick-ogrady Oct 19, 2023
3b1a351
rename address functions
patrick-ogrady Oct 19, 2023
053a9fb
e2e compiles
patrick-ogrady Oct 19, 2023
028f9a9
update short bytes trim
patrick-ogrady Oct 19, 2023
0a23686
handler compiles
patrick-ogrady Oct 19, 2023
001f1dd
add MustBech32
patrick-ogrady Oct 19, 2023
c053a90
cli updated for LoadBytes
patrick-ogrady Oct 19, 2023
3ceb724
morephus-cli builds
patrick-ogrady Oct 19, 2023
02dfdcc
update address in genesis
patrick-ogrady Oct 19, 2023
f66cbcc
separate log levels
patrick-ogrady Oct 19, 2023
92cbdc4
e2e passing
patrick-ogrady Oct 19, 2023
79d0d05
remove short bytes
patrick-ogrady Nov 4, 2023
217d597
update address parsing
patrick-ogrady Nov 4, 2023
b6441a1
link BIP-173
patrick-ogrady Nov 4, 2023
018b16e
add PrefixID func
patrick-ogrady Nov 4, 2023
338d3ca
add scope checks to chain for address
patrick-ogrady Nov 4, 2023
1875a72
update func name
patrick-ogrady Nov 4, 2023
66f4aa5
codec tests passing
patrick-ogrady Nov 4, 2023
b0804b6
update morepheus vm auth handling
patrick-ogrady Nov 4, 2023
99c88c7
remove address verification
patrick-ogrady Nov 4, 2023
44a7cf6
remove hrp from genesis
patrick-ogrady Nov 4, 2023
37d1ad2
fix genesis
patrick-ogrady Nov 4, 2023
71e0c58
morepheusvm compiles
patrick-ogrady Nov 4, 2023
d7bb894
cleaning up CLI
patrick-ogrady Nov 5, 2023
2d2265b
remove ed25519 from keystorage
patrick-ogrady Nov 5, 2023
091fc69
remove ed25519 from key
patrick-ogrady Nov 5, 2023
d8d927d
remove all references of ed25519 from cli
patrick-ogrady Nov 5, 2023
b7829ee
integration tests passing
patrick-ogrady Nov 5, 2023
21de678
e2e compiles
patrick-ogrady Nov 5, 2023
e5cdadd
implement key handling
patrick-ogrady Nov 5, 2023
3431f73
support generic key spam
patrick-ogrady Nov 5, 2023
1e544e3
e2e morpheusvm test passing
patrick-ogrady Nov 5, 2023
6795cf4
fix load test
patrick-ogrady Nov 5, 2023
31d11e3
fix lint
patrick-ogrady Nov 5, 2023
4d0911e
use Sponsor
patrick-ogrady Nov 5, 2023
4d62d4a
Merge branch 'main' into secp256r1-morpheusvm
patrick-ogrady Nov 5, 2023
19c208b
update mocks
patrick-ogrady Nov 5, 2023
148d1b9
remove payer from morpheusvm
patrick-ogrady Nov 5, 2023
53e3a72
remove ed25519 from tokenvm storage
patrick-ogrady Nov 5, 2023
c713420
auth updated
patrick-ogrady Nov 5, 2023
b6d37f1
remove all ed25519 references from actions
patrick-ogrady Nov 5, 2023
7deb7da
tokenvm compiles
patrick-ogrady Nov 5, 2023
66e5430
change to Address from AddressBytes
patrick-ogrady Nov 5, 2023
c296092
transform AddressBytes to Address
patrick-ogrady Nov 5, 2023
75dff06
more replacements
patrick-ogrady Nov 5, 2023
2e9bccf
more conversion
patrick-ogrady Nov 5, 2023
67694a4
morpheus-cli lint
patrick-ogrady Nov 5, 2023
90953fb
fix lint
patrick-ogrady Nov 5, 2023
dd4dc1a
fix handler
patrick-ogrady Nov 5, 2023
c9b85e6
remove utils from action
patrick-ogrady Nov 5, 2023
d704723
remove tutils from explorer
patrick-ogrady Nov 5, 2023
3d9a53b
cli compiles
patrick-ogrady Nov 6, 2023
724c9e6
cleanup faucet address usage
patrick-ogrady Nov 6, 2023
48f7ca7
token-feed compiles
patrick-ogrady Nov 6, 2023
27eec49
tokenvm integration passing
patrick-ogrady Nov 6, 2023
41a5e98
fix load test
patrick-ogrady Nov 6, 2023
12c3d6f
tokenvm e2e compiles
patrick-ogrady Nov 6, 2023
ad85819
e2e tests work
patrick-ogrady Nov 6, 2023
738bfa5
remove utils reference
patrick-ogrady Nov 6, 2023
5693b74
lint on cli.PrivateKey
patrick-ogrady Nov 6, 2023
34740a2
fix load test size
patrick-ogrady Nov 6, 2023
d3eb0f5
print key type in morpheus-cli
patrick-ogrady Nov 6, 2023
6e9397a
fix accounts
patrick-ogrady Nov 6, 2023
fd71f25
migrate morephus-cli to use WS
patrick-ogrady Nov 6, 2023
c716846
add missing comment
patrick-ogrady Nov 6, 2023
d97477b
handle createClient err
patrick-ogrady Nov 6, 2023
2902a34
remove extra break
patrick-ogrady Nov 6, 2023
be06d03
readme cleanup
patrick-ogrady Nov 6, 2023
082b67f
account abstraction on README
patrick-ogrady Nov 6, 2023
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
2 changes: 1 addition & 1 deletion chain/dependencies.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ type Auth interface {

// Payer is the owner of [Auth]. It is used by the mempool to ensure that there aren't too many transactions
// from a single Payer.
Payer() []byte
Payer() codec.ShortBytes

// CanDeduct returns an error if [amount] cannot be paid by [Auth].
CanDeduct(ctx context.Context, im state.Immutable, amount uint64) error
Expand Down
2 changes: 1 addition & 1 deletion cli/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
}

func (h *Handler) ImportKey(keyPath string) error {
priv, err := ed25519.LoadKey(keyPath)
priv, err := utils.LoadKey(keyPath)

Check failure on line 36 in cli/key.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

undefined: utils.LoadKey (typecheck)
if err != nil {
return err
}
Expand Down
82 changes: 82 additions & 0 deletions codec/address.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package codec

import (
"fmt"

"github.com/ava-labs/avalanchego/utils/formatting/address"
)

const (
fromBits = 8
toBits = 5
separatorLen = 1
checksumlen = 6
maxBech32Size = 90
)

// Address returns a Bech32 address from hrp and p.
// This function uses avalanchego's FormatBech32 function.
func Address(hrp string, p ShortBytes) (string, error) {
if !p.Valid() {
return "", ErrInvalidShortBytes
}
expanedNum := p.Len() * fromBits
expandedLen := expanedNum / toBits
if expanedNum%toBits != 0 {
expandedLen++
}
addrLen := len(hrp) + separatorLen + expandedLen + checksumlen
if addrLen > maxBech32Size {
return "", fmt.Errorf("%w: max=%d, requested=%d", ErrInvalidSize, maxBech32Size, addrLen)
}
return address.FormatBech32(hrp, p[:])
}

// ParseAddress parses a Bech32 encoded address string and extracts
// its bytes (ensuring they are of size [length]). If there is an error
// reading the address or the hrp value is not valid, ParseAddress returns an error.
func ParseAddress(hrp, saddr string, length int) (ShortBytes, error) {
if length > ShortBytesMaxSize {
return nil, ErrInvalidShortBytes
}
phrp, p, err := address.ParseBech32(saddr)
if err != nil {
return nil, err
}
if phrp != hrp {
return nil, ErrIncorrectHRP
}
// The parsed value may be greater than [minLength] because the
// underlying Bech32 implementation requires bytes to each encode 5 bits
// instead of 8 (and we must pad the input to ensure we fill all bytes):
// https://github.com/btcsuite/btcd/blob/902f797b0c4b3af3f7196d2f5d2343931d1b2bdf/btcutil/bech32/bech32.go#L325-L331
if len(p) < length {
return nil, ErrInsufficientLength
}
return p[:length], nil
}

// ParseAnyAddress parses a Bech32 encoded address string and extracts
// its bytes. If there is an error reading the address or the hrp value
// is not valid, ParseAnyAddress returns an error.
//
// The ShortBytes returned may contain extra padding. If the parsed
// length is greater than [ShortBytesMaxSize], it is truncated (should
// not be possible because max string length is 90).
func ParseAnyAddress(hrp, saddr string) (ShortBytes, error) {
phrp, p, err := address.ParseBech32(saddr)
if err != nil {
return nil, err
}
if phrp != hrp {
return nil, ErrIncorrectHRP
}
// The parsed value may be greater than [ShortBytesMaxSize] because the
// underlying Bech32 implementation requires bytes to each encode 5 bits
// instead of 8 (and we must pad the input to ensure we fill all bytes):
// https://github.com/btcsuite/btcd/blob/902f797b0c4b3af3f7196d2f5d2343931d1b2bdf/btcutil/bech32/bech32.go#L325-L331
if len(p) > ShortBytesMaxSize {
p = p[:ShortBytesMaxSize]
}
return p, nil
}
71 changes: 71 additions & 0 deletions codec/address_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package codec

import (
"bytes"
"testing"

"github.com/ava-labs/avalanchego/ids"
"github.com/stretchr/testify/require"
)

const hrp = "blah"

func TestIDAddress(t *testing.T) {
require := require.New(t)

id := ids.GenerateTestID()
addr, err := Address(hrp, id[:])
require.NoError(err)

sb, err := ParseAddress(hrp, addr, ids.IDLen)
require.NoError(err)
require.True(bytes.Equal(id[:], sb[:]))
}

func TestInvalidAddressHRP(t *testing.T) {
require := require.New(t)
addr := "blah1859dz2uwazfgahey3j53ef2kqrans0c8cv4l78tda3rjkfw0txns8u2e8k"

_, err := ParseAddress("test", addr, ids.IDLen)
require.ErrorIs(err, ErrIncorrectHRP)
}

func TestInvalidAddressChecksum(t *testing.T) {
require := require.New(t)
addr := "blah1859dz2uwazfgahey3j53ef2kqrans0c8cv4l78tda3rjkfw0txns8u2e7k"

_, err := ParseAddress(hrp, addr, ids.IDLen)
require.ErrorContains(err, "invalid checksum")
}

func TestMaxAddress(t *testing.T) {
require := require.New(t)

b := make([]byte, 49)
b[0] = 1
b[49-1] = 1
addr, err := Address(hrp, b)
require.NoError(err)

sb, err := ParseAddress(hrp, addr, 49)
require.NoError(err)
require.True(bytes.Equal(b[:], sb[:]))

Check failure on line 52 in codec/address_test.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unslice: could simplify b[:] to b (gocritic)
}

func TestCreateLargeAddress(t *testing.T) {
require := require.New(t)

b := make([]byte, 50)
b[0] = 1
b[50-1] = 1
_, err := Address(hrp, b)
require.ErrorIs(err, ErrInvalidSize)
}

func TestParseLargeAddress(t *testing.T) {
require := require.New(t)

addr := "blah1859dz2uwazfgahey3j53ef2kqrans0c8cv4l78tda3rjkfw0txnxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxs8u2e7k"
_, err := ParseAddress(hrp, addr, 60)
require.ErrorContains(err, "invalid bech32 string length")
}
13 changes: 8 additions & 5 deletions codec/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ package codec
import "errors"

var (
ErrTooManyItems = errors.New("too many items")
ErrDuplicateItem = errors.New("duplicate item")
ErrFieldNotPopulated = errors.New("field is not populated")
ErrInvalidBitset = errors.New("invalid bitset")
ErrTooLarge = errors.New("too large")
ErrTooManyItems = errors.New("too many items")
ErrDuplicateItem = errors.New("duplicate item")
ErrFieldNotPopulated = errors.New("field is not populated")
ErrInvalidBitset = errors.New("invalid bitset")
ErrInvalidShortBytes = errors.New("invalid short bytes")
ErrIncorrectHRP = errors.New("incorrect hrp")
ErrInsufficientLength = errors.New("insufficient length")
ErrInvalidSize = errors.New("invalid size")
)
21 changes: 21 additions & 0 deletions codec/hex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package codec

import "encoding/hex"

// ToHex converts a PrivateKey to a hex string.
func ToHex(b []byte) string {
return hex.EncodeToString(b[:])

Check failure on line 7 in codec/hex.go

View workflow job for this annotation

GitHub Actions / hypersdk-lint

unslice: could simplify b[:] to b (gocritic)
}

// LoadHex Converts hex encoded string into bytes. Returns
// an error if key is invalid.
func LoadHex(s string, expectedSize int) ([]byte, error) {
bytes, err := hex.DecodeString(s)
if err != nil {
return nil, err
}
if expectedSize != -1 && len(bytes) != expectedSize {
return nil, ErrInvalidSize
}
return bytes, nil
}
22 changes: 0 additions & 22 deletions codec/optional_packer.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/avalanchego/utils/set"
"github.com/ava-labs/hypersdk/consts"
"github.com/ava-labs/hypersdk/crypto/ed25519"
)

// OptionalPacker defines a struct that includes a Packer [ip], a bitset
Expand Down Expand Up @@ -94,27 +93,6 @@ func (o *OptionalPacker) UnpackID(dest *ids.ID) {
}
}

// PackPublicKey packs [pk] into OptionalPacker if [pk] is not an empty PublicKey.
// Updates the bitset and offset accordingly.
func (o *OptionalPacker) PackPublicKey(pk ed25519.PublicKey) {
if pk == ed25519.EmptyPublicKey {
o.skipBit()
return
}
o.ip.PackPublicKey(pk)
o.setBit()
}

// UnpackPublicKey unpacks a PublicKey into [dest] if the bitset is set at
// the current offset. Increments offset regardless.
func (o *OptionalPacker) UnpackPublicKey(dest *ed25519.PublicKey) {
if o.checkBit() {
o.ip.UnpackPublicKey(true, dest)
} else {
*dest = ed25519.EmptyPublicKey
}
}

// PackUint64 packs [l] into OptionalPacker if [l] is not an 0.
// Updates the bitset and offset accordingly.
func (o *OptionalPacker) PackUint64(l uint64) {
Expand Down
51 changes: 0 additions & 51 deletions codec/optional_packer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (

"github.com/ava-labs/avalanchego/ids"
"github.com/ava-labs/hypersdk/consts"
"github.com/ava-labs/hypersdk/crypto/ed25519"
"github.com/stretchr/testify/require"
)

Expand All @@ -25,56 +24,6 @@ func (o *OptionalPacker) toReader() *OptionalPacker {
return pr.NewOptionalReader()
}

func TestOptionalPackerWriter(t *testing.T) {
// Initializes empty writer with a limit two byte limit
require := require.New(t)
opw := NewOptionalWriter(10_000)
require.Empty(opw.ip.Bytes())
var pubKey ed25519.PublicKey
copy(pubKey[:], TestPublicKey)
// Fill OptionalPacker
i := 0
for i <= consts.MaxUint64Offset {
opw.PackPublicKey(pubKey)
i += 1
}
require.Equal(
(consts.MaxUint64Offset+1)*ed25519.PublicKeyLen,
len(opw.ip.Bytes()),
"Bytes not added correctly.",
)
require.NoError(opw.Err(), "Error packing bytes.")
opw.PackPublicKey(pubKey)
require.ErrorIs(opw.Err(), ErrTooManyItems, "Error not thrown after over packing.")
}

func TestOptionalPackerPublicKey(t *testing.T) {
require := require.New(t)
opw := NewOptionalWriter(10_000)
var pubKey ed25519.PublicKey
copy(pubKey[:], TestPublicKey)
t.Run("Pack", func(t *testing.T) {
// Pack empty
opw.PackPublicKey(ed25519.EmptyPublicKey)
require.Empty(opw.ip.Bytes(), "PackPublickey packed an empty ID.")
// Pack ID
opw.PackPublicKey(pubKey)
require.Equal(TestPublicKey, opw.ip.Bytes(), "PackPublickey did not set bytes correctly.")
})
t.Run("Unpack", func(t *testing.T) {
// Setup optional reader
opr := opw.toReader()
var unpackedPubkey ed25519.PublicKey
// Unpack
opr.UnpackPublicKey(&unpackedPubkey)
require.Equal(ed25519.EmptyPublicKey[:], unpackedPubkey[:], "PublicKey unpacked correctly")
opr.UnpackPublicKey(&unpackedPubkey)
require.Equal(pubKey, unpackedPubkey, "PublicKey unpacked correctly")
opr.Done()
require.NoError(opr.Err())
})
}

func TestOptionalPackerID(t *testing.T) {
require := require.New(t)
opw := NewOptionalWriter(10_000)
Expand Down
35 changes: 4 additions & 31 deletions codec/packer.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ import (
"github.com/ava-labs/avalanchego/utils/wrappers"

"github.com/ava-labs/hypersdk/consts"
"github.com/ava-labs/hypersdk/crypto/ed25519"
"github.com/ava-labs/hypersdk/window"
)

// Packer is a wrapper struct for the Packer struct
// from avalanchego/utils/wrappers/packing.go. It adds methods to
// pack/unpack ids, PublicKeys and Signatures. A bool [required] parameter is
// from avalanchego/utils/wrappers/packing.go. A bool [required] parameter is
// added to many unpacking methods, which signals the packer to add an error
// if the expected method does not unpack properly.
type Packer struct {
Expand Down Expand Up @@ -73,9 +71,9 @@ func (p *Packer) PackFixedBytes(b []byte) {
}

func (p *Packer) PackShortBytes(b ShortBytes) {
l := len(b)
if l > ShortBytesMaxSize {
p.addErr(fmt.Errorf("%w: ShortBytes is too large (found=%d)", ErrTooLarge, len(b)))
l := b.Len()
if !b.Valid() {
p.addErr(fmt.Errorf("%w: found=%d", ErrInvalidShortBytes, len(b)))
return
}
p.PackByte(uint8(l))
Expand Down Expand Up @@ -134,31 +132,6 @@ func (p *Packer) UnpackInt64(required bool) int64 {
return int64(v)
}

func (p *Packer) PackPublicKey(src ed25519.PublicKey) {
p.p.PackFixedBytes(src[:])
}

// UnpackPublicKey ed25519.PublicKey into [dest].
func (p *Packer) UnpackPublicKey(required bool, dest *ed25519.PublicKey) {
copy((*dest)[:], p.p.UnpackFixedBytes(ed25519.PublicKeyLen))
if required && *dest == ed25519.EmptyPublicKey {
p.addErr(fmt.Errorf("%w: PublicKey field is not populated", ErrFieldNotPopulated))
}
}

func (p *Packer) PackSignature(src ed25519.Signature) {
p.p.PackFixedBytes(src[:])
}

// UnpackPublicKey ed25519.Signature into [dest].
// TODO: should add required param?
func (p *Packer) UnpackSignature(dest *ed25519.Signature) {
copy((*dest)[:], p.p.UnpackFixedBytes(ed25519.SignatureLen))
if *dest == ed25519.EmptySignature {
p.addErr(fmt.Errorf("%w: Signature field is not populated", ErrFieldNotPopulated))
}
}

func (p *Packer) PackInt(v int) {
p.p.PackInt(uint32(v))
}
Expand Down
Loading
Loading