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 Mar 6, 2024
1 parent 79637ab commit b9f629a
Show file tree
Hide file tree
Showing 19 changed files with 345 additions and 135 deletions.
22 changes: 10 additions & 12 deletions api/core.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,6 @@ type (
Version string `serix:",lenPrefix=uint8"`
// The current status of this node.
Status *InfoResNodeStatus `serix:""`
// The metrics of this node.
Metrics *InfoResNodeMetrics `serix:""`
// The protocol parameters used by this node.
ProtocolParameters []*InfoResProtocolParameters `serix:",lenPrefix=uint8"`
// The base token of the network.
Expand Down Expand Up @@ -507,16 +505,6 @@ type (
PruningEpoch iotago.EpochIndex `serix:""`
}

// InfoResNodeMetrics defines the metrics of a node in the InfoResponse.
InfoResNodeMetrics struct {
// The current rate of new blocks per second, it's updated when a commitment is committed.
BlocksPerSecond float64 `serix:""`
// The current rate of confirmed blocks per second, it's updated when a commitment is committed.
ConfirmedBlocksPerSecond float64 `serix:""`
// The ratio of confirmed blocks in relation to new blocks up until the latest commitment is committed.
ConfirmationRate float64 `serix:""`
}

// InfoResBaseToken defines the base token of the node in the InfoResponse.
InfoResBaseToken struct {
// The base token name.
Expand All @@ -531,6 +519,16 @@ type (
Decimals uint32 `serix:""`
}

// NetworkMetricsResponse defines the network metrics response.
NetworkMetricsResponse struct {
// The current rate of new blocks per second, it's updated when a commitment is committed.
BlocksPerSecond float64 `serix:""`
// The current rate of confirmed blocks per second, it's updated when a commitment is committed.
ConfirmedBlocksPerSecond float64 `serix:""`
// The ratio of confirmed blocks in relation to new blocks up until the latest commitment is committed.
ConfirmationRate float64 `serix:""`
}

// IssuanceBlockHeaderResponse defines the response of a GET block issuance REST API call.
IssuanceBlockHeaderResponse struct {
// StrongParents are the strong parents of the block.
Expand Down
41 changes: 25 additions & 16 deletions api/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@ func Test_CoreAPIDeSerialize(t *testing.T) {
LatestConfirmedBlockSlot: tpkg.RandSlot(),
PruningEpoch: tpkg.RandEpoch(),
},
Metrics: &api.InfoResNodeMetrics{
BlocksPerSecond: 1.1,
ConfirmedBlocksPerSecond: 2.2,
ConfirmationRate: 3.3,
},
ProtocolParameters: []*api.InfoResProtocolParameters{
{
StartEpoch: tpkg.RandEpoch(),
Expand All @@ -56,6 +51,17 @@ func Test_CoreAPIDeSerialize(t *testing.T) {
SeriErr: nil,
DeSeriErr: nil,
},
{
Name: "ok - NetworkMetricsResponse",
Source: &api.NetworkMetricsResponse{
BlocksPerSecond: 1.1,
ConfirmedBlocksPerSecond: 2.2,
ConfirmationRate: 3.3,
},
Target: &api.NetworkMetricsResponse{},
SeriErr: nil,
DeSeriErr: nil,
},
{
Name: "ok - IssuanceBlockHeaderResponse",
Source: &api.IssuanceBlockHeaderResponse{
Expand Down Expand Up @@ -305,11 +311,6 @@ func Test_CoreAPIJSONSerialization(t *testing.T) {
LatestConfirmedBlockSlot: 3,
PruningEpoch: 4,
},
Metrics: &api.InfoResNodeMetrics{
BlocksPerSecond: 1.1,
ConfirmedBlocksPerSecond: 2.2,
ConfirmationRate: 3.3,
},
ProtocolParameters: []*api.InfoResProtocolParameters{
{
StartEpoch: 0,
Expand Down Expand Up @@ -339,11 +340,6 @@ func Test_CoreAPIJSONSerialization(t *testing.T) {
"latestConfirmedBlockSlot": 3,
"pruningEpoch": 4
},
"metrics": {
"blocksPerSecond": "1.1E+00",
"confirmedBlocksPerSecond": "2.2E+00",
"confirmationRate": "3.3E+00"
},
"protocolParameters": [
{
"startEpoch": 0,
Expand Down Expand Up @@ -435,6 +431,19 @@ func Test_CoreAPIJSONSerialization(t *testing.T) {
"subunit": "glow",
"decimals": 6
}
}`,
},
{
Name: "ok - NetworkMetricsResponse",
Source: &api.NetworkMetricsResponse{
BlocksPerSecond: 1.1,
ConfirmedBlocksPerSecond: 2.2,
ConfirmationRate: 3.3,
},
Target: `{
"blocksPerSecond": "1.1",
"confirmedBlocksPerSecond": "2.2",
"confirmationRate": "3.3"
}`,
},
{
Expand Down Expand Up @@ -541,7 +550,7 @@ func Test_CoreAPIJSONSerialization(t *testing.T) {
"transactionId": "0x010000000000000000000000000000000000000000000000000000000000000000000000",
"transactionState": "failed",
"earliestAttachmentSlot": 5,
"transactionFailureReason": 57,
"transactionFailureReason": 58,
"transactionFailureDetails": "details"
}`,
},
Expand Down
8 changes: 8 additions & 0 deletions api/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,13 @@ const (
// MIMEApplicationVendorIOTASerializerV2 => bytes.
CoreEndpointInfo = "/info"

// CoreEndpointNetworkMetrics is the endpoint for getting the network metrics.
// GET returns the network metrics.
// "Accept" header:
// MIMEApplicationJSON => json.
// MIMEApplicationVendorIOTASerializerV2 => bytes.
CoreEndpointNetworkMetrics = "/network/metrics"

// CoreEndpointBlocks is the endpoint for sending new blocks.
// POST sends a single new block and returns the new block ID.
// "Content-Type" header:
Expand Down Expand Up @@ -282,6 +289,7 @@ const (

var (
CoreRouteInfo = route(CorePluginName, CoreEndpointInfo)
CoreRouteNetworkMetrics = route(CorePluginName, CoreEndpointNetworkMetrics)
CoreRouteBlocks = route(CorePluginName, CoreEndpointBlocks)
CoreRouteBlock = route(CorePluginName, CoreEndpointBlock)
CoreRouteBlockMetadata = route(CorePluginName, CoreEndpointBlockMetadata)
Expand Down
2 changes: 1 addition & 1 deletion block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ func createBlockWithParents(t *testing.T, strongParents, weakParents, shallowLik
WeakParents(weakParents).
ShallowLikeParents(shallowLikeParent).
IssuingTime(time.Now()).
SlotCommitmentID(iotago.NewCommitment(apiForSlot.Version(), apiForSlot.TimeProvider().SlotFromTime(time.Now())-apiForSlot.ProtocolParameters().MinCommittableAge(), iotago.CommitmentID{}, iotago.Identifier{}, 0, 0).MustID()).
SlotCommitmentID(iotago.NewCommitment(apiForSlot.Version(), apiForSlot.TimeProvider().CurrentSlot()-apiForSlot.ProtocolParameters().MinCommittableAge(), iotago.CommitmentID{}, iotago.Identifier{}, 0, 0).MustID()).
Build()
require.NoError(t, err)

Expand Down
12 changes: 12 additions & 0 deletions builder/transaction_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,9 +703,21 @@ func (b *TransactionBuilder) build(signEssence bool) (*iotago.SignedTransaction,
unlockedChains: map[string]int{},
}

// resolveUnderlyingAddress returns the underlying address in case of a restricted address.
// this way we handle restricted addresses like normal addresses in the unlock logic.
resolveUnderlyingAddress := func(addr iotago.Address) iotago.Address {
switch addr := addr.(type) {
case *iotago.RestrictedAddress:
return addr.Address
default:
return addr
}
}

for inputIndex, inputRef := range b.transaction.TransactionEssence.Inputs {
//nolint:forcetypeassert // we can safely assume that this is an UTXOInput
owner := b.inputOwner[inputRef.(*iotago.UTXOInput).OutputID()]
owner = resolveUnderlyingAddress(owner)

chainAddr, isChainAddress := owner.(iotago.ChainAddress)
if isChainAddress {
Expand Down
108 changes: 60 additions & 48 deletions builder/transaction_builder_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//nolint:scopelint
//nolint:scopelint,forcetypeassert
package builder_test

import (
Expand All @@ -15,9 +15,18 @@ import (

func TestTransactionBuilder(t *testing.T) {
prvKey := tpkg.RandEd25519PrivateKey()
//nolint:forcetypeassert // we can safely assume that this is an ed25519.PublicKey
inputAddr := iotago.Ed25519AddressFromPubKey(prvKey.Public().(ed25519.PublicKey))
addrKeys := iotago.AddressKeys{Address: inputAddr, Keys: prvKey}
pubKey := prvKey.Public().(ed25519.PublicKey)
inputAddrEd25519 := iotago.Ed25519AddressFromPubKey(pubKey)
inputAddrRestricted := iotago.RestrictedAddressWithCapabilities(inputAddrEd25519, iotago.WithAddressCanReceiveAnything())
inputAddrImplicitAccountCreation := iotago.ImplicitAccountCreationAddressFromPubKey(pubKey)
signer := iotago.NewInMemoryAddressSignerFromEd25519PrivateKeys(prvKey)

output := &iotago.BasicOutput{
Amount: 50,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
}

type test struct {
name string
Expand All @@ -26,21 +35,44 @@ func TestTransactionBuilder(t *testing.T) {
}

tests := []*test{
// ok - 1 input/output
// ok - 1 input/output - Ed25519 address
func() *test {
inputUTXO1 := &iotago.UTXOInput{TransactionID: tpkg.Rand36ByteArray(), TransactionOutputIndex: 0}
input := tpkg.RandBasicOutput(iotago.AddressEd25519)
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, iotago.NewInMemoryAddressSigner(addrKeys)).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputUTXO1.OutputID(), Input: input}).
AddOutput(&iotago.BasicOutput{
Amount: 50,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
})
input := tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrEd25519)
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, signer).
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputUTXO1.OutputID(), Input: input}).
AddOutput(output)

return &test{
name: "ok - 1 input/output - Ed25519 address",
builder: bdl,
}
}(),

// ok - 1 input/output - Restricted address with underlying Ed25519 address
func() *test {
inputUTXO1 := &iotago.UTXOInput{TransactionID: tpkg.Rand36ByteArray(), TransactionOutputIndex: 0}
input := tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrRestricted)
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, signer).
AddInput(&builder.TxInput{UnlockTarget: inputAddrRestricted, InputID: inputUTXO1.OutputID(), Input: input}).
AddOutput(output)

return &test{
name: "ok - 1 input/output - Restricted address with underlying Ed25519 address",
builder: bdl,
}
}(),

// ok - 1 input/output - Implicit account creation address
func() *test {
inputUTXO1 := &iotago.UTXOInput{TransactionID: tpkg.Rand36ByteArray(), TransactionOutputIndex: 0}
input := tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrImplicitAccountCreation)
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, signer).
AddInput(&builder.TxInput{UnlockTarget: inputAddrImplicitAccountCreation, InputID: inputUTXO1.OutputID(), Input: input}).
AddOutput(output)

return &test{
name: "ok - 1 input/output",
name: "ok - 1 input/output - Implicit account creation address",
builder: bdl,
}
}(),
Expand All @@ -57,13 +89,13 @@ func TestTransactionBuilder(t *testing.T) {
var (
basicOutput = &iotago.BasicOutput{
Amount: 1000,
UnlockConditions: iotago.BasicOutputUnlockConditions{&iotago.AddressUnlockCondition{Address: inputAddr}},
UnlockConditions: iotago.BasicOutputUnlockConditions{&iotago.AddressUnlockCondition{Address: inputAddrEd25519}},
}

nftOutput = &iotago.NFTOutput{
Amount: 1000,
NFTID: tpkg.Rand32ByteArray(),
UnlockConditions: iotago.NFTOutputUnlockConditions{&iotago.AddressUnlockCondition{Address: inputAddr}},
UnlockConditions: iotago.NFTOutputUnlockConditions{&iotago.AddressUnlockCondition{Address: inputAddrEd25519}},
Features: nil,
ImmutableFeatures: nil,
}
Expand All @@ -82,17 +114,12 @@ func TestTransactionBuilder(t *testing.T) {
}
)

bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, iotago.NewInMemoryAddressSigner(addrKeys)).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputID1.OutputID(), Input: basicOutput}).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputID2.OutputID(), Input: nftOutput}).
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, signer).
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputID1.OutputID(), Input: basicOutput}).
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputID2.OutputID(), Input: nftOutput}).
AddInput(&builder.TxInput{UnlockTarget: nftOutput.ChainID().ToAddress(), InputID: inputID3.OutputID(), Input: accountOwnedByNFT}).
AddInput(&builder.TxInput{UnlockTarget: accountOwnedByNFT.ChainID().ToAddress(), InputID: inputID4.OutputID(), Input: basicOwnedByAccount}).
AddOutput(&iotago.BasicOutput{
Amount: 4000,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
})
AddOutput(output)

return &test{
name: "ok - mix basic+chain outputs",
Expand All @@ -104,14 +131,9 @@ func TestTransactionBuilder(t *testing.T) {
func() *test {
inputUTXO1 := &iotago.UTXOInput{TransactionID: tpkg.Rand36ByteArray(), TransactionOutputIndex: 0}

bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, iotago.NewInMemoryAddressSigner(addrKeys)).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputUTXO1.OutputID(), Input: tpkg.RandBasicOutput(iotago.AddressEd25519)}).
AddOutput(&iotago.BasicOutput{
Amount: 50,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
}).
bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, signer).
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputUTXO1.OutputID(), Input: tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrEd25519)}).
AddOutput(output).
AddTaggedDataPayload(&iotago.TaggedData{Tag: []byte("index"), Data: nil})

return &test{
Expand All @@ -131,13 +153,8 @@ func TestTransactionBuilder(t *testing.T) {
wrongAddrKeys := iotago.AddressKeys{Address: wrongAddr, Keys: wrongAddress}

bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, iotago.NewInMemoryAddressSigner(wrongAddrKeys)).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputUTXO1.OutputID(), Input: tpkg.RandBasicOutput(iotago.AddressEd25519)}).
AddOutput(&iotago.BasicOutput{
Amount: 50,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
})
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputUTXO1.OutputID(), Input: tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrEd25519)}).
AddOutput(output)

return &test{
name: "err - missing address keys (wrong address)",
Expand All @@ -151,13 +168,8 @@ func TestTransactionBuilder(t *testing.T) {
inputUTXO1 := &iotago.UTXOInput{TransactionID: tpkg.Rand36ByteArray(), TransactionOutputIndex: 0}

bdl := builder.NewTransactionBuilder(tpkg.ZeroCostTestAPI, iotago.NewInMemoryAddressSigner()).
AddInput(&builder.TxInput{UnlockTarget: inputAddr, InputID: inputUTXO1.OutputID(), Input: tpkg.RandBasicOutput(iotago.AddressEd25519)}).
AddOutput(&iotago.BasicOutput{
Amount: 50,
UnlockConditions: iotago.BasicOutputUnlockConditions{
&iotago.AddressUnlockCondition{Address: tpkg.RandEd25519Address()},
},
})
AddInput(&builder.TxInput{UnlockTarget: inputAddrEd25519, InputID: inputUTXO1.OutputID(), Input: tpkg.RandOutputOnAddress(iotago.OutputBasic, inputAddrEd25519)}).
AddOutput(output)

return &test{
name: "err - missing address keys (no keys given at all)",
Expand Down
5 changes: 5 additions & 0 deletions feat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) {
bik3,
}),
}
t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput())
},
),
Target: &iotago.SignedTransaction{},
Expand All @@ -442,6 +443,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) {
bik3,
}),
}
t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput())
}),
Target: &iotago.SignedTransaction{},
SeriErr: iotago.ErrArrayValidationOrderViolatesLexicalOrder,
Expand All @@ -458,6 +460,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) {
bik2,
}),
}
t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput())
}),
Target: &iotago.SignedTransaction{},
SeriErr: iotago.ErrArrayValidationViolatesUniqueness,
Expand All @@ -469,6 +472,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) {
t.Outputs = iotago.TxEssenceOutputs{
accountWithKeys(iotago.BlockIssuerKeys{}),
}
t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput())
}),
Target: &iotago.SignedTransaction{},
SeriErr: serializer.ErrArrayValidationMinElementsNotReached,
Expand All @@ -480,6 +484,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) {
t.Outputs = iotago.TxEssenceOutputs{
accountWithKeys(tpkg.RandBlockIssuerKeys(iotago.MaxBlockIssuerKeysCount + 1)),
}
t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput())
}),
Target: &iotago.SignedTransaction{},
SeriErr: serializer.ErrArrayValidationMaxElementsExceeded,
Expand Down
Loading

0 comments on commit b9f629a

Please sign in to comment.