Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:iotaledger/iota.go into feat/blo…
Browse files Browse the repository at this point in the history
…ckstate
  • Loading branch information
muXxer committed Feb 28, 2024
2 parents 6459af9 + 48e711a commit 4f9efbe
Show file tree
Hide file tree
Showing 47 changed files with 1,427 additions and 1,204 deletions.
2 changes: 0 additions & 2 deletions address.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,8 +166,6 @@ type ChainID interface {
ToAddress() ChainAddress
// Empty tells whether the ChainID is empty.
Empty() bool
// Key returns a key to use to index this ChainID.
Key() interface{}
// ToHex returns the hex representation of the ChainID.
ToHex() string
}
Expand Down
70 changes: 54 additions & 16 deletions address_signer.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iotago

import (
"crypto"
"crypto/ed25519"

"github.com/iotaledger/hive.go/ierrors"
Expand All @@ -15,8 +16,14 @@ var (

// AddressSigner produces signatures for messages which get verified against a given address.
type AddressSigner interface {
// SignerUIDForAddress returns the signer unique identifier for a given address.
// This can be used to identify the uniqueness of the signer in the unlocks (e.g. unique public key).
SignerUIDForAddress(addr Address) (Identifier, error)
// Sign produces the signature for the given message.
Sign(addr Address, msg []byte) (signature Signature, err error)
// EmptySignatureForAddress returns an empty signature for the given address.
// This can be used to calculate the WorkScore of transactions without actually signing the transaction.
EmptySignatureForAddress(addr Address) (signature Signature, err error)
}

// AddressSignerFunc implements the AddressSigner interface.
Expand Down Expand Up @@ -91,9 +98,9 @@ type InMemoryAddressSigner struct {
addrKeys map[string]interface{}
}

func (s *InMemoryAddressSigner) Sign(addr Address, msg []byte) (signature Signature, err error) {

signatureForEd25519Address := func(edAddr DirectUnlockableAddress, msg []byte) (signature Signature, err error) {
// privateKeyForAddress returns the private key for the given address.
func (s *InMemoryAddressSigner) privateKeyForAddress(addr Address) (crypto.PrivateKey, error) {
privateKeyForEd25519Address := func(edAddr DirectUnlockableAddress) (ed25519.PrivateKey, error) {
maybePrvKey, ok := s.addrKeys[edAddr.Key()]
if !ok {
return nil, ierrors.Errorf("can't sign message for Ed25519 address: %w", ErrAddressKeysNotMapped)
Expand All @@ -104,38 +111,69 @@ func (s *InMemoryAddressSigner) Sign(addr Address, msg []byte) (signature Signat
return nil, ierrors.Wrapf(ErrAddressKeysWrongType, "Ed25519 address needs to have a %T private key mapped but got %T", ed25519.PrivateKey{}, maybePrvKey)
}

ed25519Sig := &Ed25519Signature{}
copy(ed25519Sig.Signature[:], ed25519.Sign(prvKey, msg))
//nolint:forcetypeassert // we can safely assume that this is an ed25519.PublicKey
copy(ed25519Sig.PublicKey[:], prvKey.Public().(ed25519.PublicKey))

return ed25519Sig, nil
return prvKey, nil
}

switch address := addr.(type) {
case *Ed25519Address:
return signatureForEd25519Address(address, msg)
return privateKeyForEd25519Address(address)

case *RestrictedAddress:
switch underlyingAddr := address.Address.(type) {
case *Ed25519Address:
return signatureForEd25519Address(underlyingAddr, msg)
return privateKeyForEd25519Address(underlyingAddr)
default:
return nil, ierrors.Wrapf(ErrUnknownAddrType, "unknown underlying address type %T in restricted address", addr)
}

case *ImplicitAccountCreationAddress:
return signatureForEd25519Address(address, msg)
return privateKeyForEd25519Address(address)

default:
return nil, ierrors.Wrapf(ErrUnknownAddrType, "type %T", addr)
}
}

// EmptyAddressSigner returns an empty signature for the given address.
// This can be used to calculate the WorkScore of transactions without actually signing the transaction.
type EmptyAddressSigner struct{}
// SignerUIDForAddress returns the signer unique identifier for a given address.
// This can be used to identify the uniqueness of the signer in the unlocks.
func (s *InMemoryAddressSigner) SignerUIDForAddress(addr Address) (Identifier, error) {
prvKey, err := s.privateKeyForAddress(addr)
if err != nil {
return EmptyIdentifier, ierrors.Errorf("can't get private key for address: %w", err)
}

ed25519PrvKey, ok := prvKey.(ed25519.PrivateKey)
if !ok {
return EmptyIdentifier, ierrors.Wrapf(ErrAddressKeysWrongType, "Ed25519 address needs to have a %T private key mapped but got %T", ed25519.PrivateKey{}, prvKey)
}

// the UID is the blake2b 256 hash of the public key
//nolint:forcetypeassert // we can safely assume that this is an ed25519.PublicKey
return IdentifierFromData(ed25519PrvKey.Public().(ed25519.PublicKey)), nil
}

func (s *InMemoryAddressSigner) Sign(addr Address, msg []byte) (signature Signature, err error) {
prvKey, err := s.privateKeyForAddress(addr)
if err != nil {
return nil, ierrors.Errorf("can't sign message for address: %w", err)
}

ed25519PrvKey, ok := prvKey.(ed25519.PrivateKey)
if !ok {
return nil, ierrors.Wrapf(ErrAddressKeysWrongType, "Ed25519 address needs to have a %T private key mapped but got %T", ed25519.PrivateKey{}, prvKey)
}

ed25519Sig := &Ed25519Signature{}
copy(ed25519Sig.Signature[:], ed25519.Sign(ed25519PrvKey, msg))
//nolint:forcetypeassert // we can safely assume that this is an ed25519.PublicKey
copy(ed25519Sig.PublicKey[:], ed25519PrvKey.Public().(ed25519.PublicKey))

func (s *EmptyAddressSigner) Sign(addr Address, _ []byte) (signature Signature, err error) {
return ed25519Sig, nil
}

// EmptySignatureForAddress returns an empty signature for the given address.
// This can be used to calculate the WorkScore of transactions without actually signing the transaction.
func (s *InMemoryAddressSigner) EmptySignatureForAddress(addr Address) (signature Signature, err error) {
switch address := addr.(type) {
case *Ed25519Address:
return &Ed25519Signature{}, nil
Expand Down
44 changes: 22 additions & 22 deletions block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ func TestBlock_TransactionCreationTime(t *testing.T) {
iotago.WithLivenessOptions(15, 30, 7, 21, 60),
), 0)

creationSlotTooRecent, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
creationSlotTooRecent, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Expand All @@ -313,49 +313,49 @@ func TestBlock_TransactionCreationTime(t *testing.T) {
AddOutput(output).
SetCreationSlot(101).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(78, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.ErrorIs(t, createBlockAtSlotWithPayload(t, 100, 79, creationSlotTooRecent, apiProvider), iotago.ErrTransactionCreationSlotTooRecent)

creationSlotCorrectEqual, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
creationSlotCorrectEqual, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
SetCreationSlot(100).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.NoError(t, createBlockAtSlotWithPayload(t, 100, 89, creationSlotCorrectEqual, apiProvider))

creationSlotCorrectSmallerThanCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
creationSlotCorrectSmallerThanCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
SetCreationSlot(1).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.NoError(t, createBlockAtSlotWithPayload(t, 100, 89, creationSlotCorrectSmallerThanCommitment, apiProvider))

creationSlotCorrectLargerThanCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
creationSlotCorrectLargerThanCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
SetCreationSlot(99).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

Expand Down Expand Up @@ -430,99 +430,99 @@ func TestBlock_TransactionCommitmentInput(t *testing.T) {
iotago.WithLivenessOptions(15, 30, 11, 21, 60),
), 0)

commitmentInputTooOld, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentInputTooOld, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(78, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.ErrorIs(t, createBlockAtSlotWithPayload(t, 100, 79, commitmentInputTooOld, apiProvider), iotago.ErrCommitmentInputTooOld)

commitmentInputTooRecent, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentInputTooRecent, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(90, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.ErrorIs(t, createBlockAtSlotWithPayload(t, 100, 89, commitmentInputTooRecent, apiProvider), iotago.ErrCommitmentInputTooRecent)

commitmentInputNewerThanBlockCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentInputNewerThanBlockCommitment, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(85, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.ErrorIs(t, createBlockAtSlotWithPayload(t, 100, 79, commitmentInputNewerThanBlockCommitment, apiProvider), iotago.ErrCommitmentInputNewerThanCommitment)

commitmentCorrect, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentCorrect, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(79, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.NoError(t, createBlockAtSlotWithPayload(t, 100, 89, commitmentCorrect, apiProvider))

commitmentCorrectOldest, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentCorrectOldest, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(79, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.NoError(t, createBlockAtSlotWithPayload(t, 100, 79, commitmentCorrectOldest, apiProvider))

commitmentCorrectNewest, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentCorrectNewest, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(89, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

require.NoError(t, createBlockAtSlotWithPayload(t, 100, 89, commitmentCorrectNewest, apiProvider))

commitmentCorrectMiddle, err := builder.NewTransactionBuilder(apiProvider.LatestAPI()).
commitmentCorrectMiddle, err := builder.NewTransactionBuilder(apiProvider.LatestAPI(), iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])})).
AddInput(&builder.TxInput{
UnlockTarget: addr,
InputID: tpkg.RandOutputID(0),
Input: output,
}).
AddOutput(output).
AddCommitmentInput(&iotago.CommitmentInput{CommitmentID: iotago.NewCommitmentID(85, tpkg.Rand32ByteArray())}).
Build(iotago.NewInMemoryAddressSigner(iotago.AddressKeys{Address: addr, Keys: ed25519.PrivateKey(keyPair.PrivateKey[:])}))
Build()

require.NoError(t, err)

Expand Down
Loading

0 comments on commit 4f9efbe

Please sign in to comment.