diff --git a/api/core.go b/api/core.go index e0e0679ad..b1407195d 100644 --- a/api/core.go +++ b/api/core.go @@ -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. @@ -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. @@ -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. diff --git a/api/core_test.go b/api/core_test.go index 384917313..8323e6a52 100644 --- a/api/core_test.go +++ b/api/core_test.go @@ -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(), @@ -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{ @@ -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, @@ -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, @@ -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" }`, }, { @@ -541,7 +550,7 @@ func Test_CoreAPIJSONSerialization(t *testing.T) { "transactionId": "0x010000000000000000000000000000000000000000000000000000000000000000000000", "transactionState": "failed", "earliestAttachmentSlot": 5, - "transactionFailureReason": 57, + "transactionFailureReason": 58, "transactionFailureDetails": "details" }`, }, diff --git a/api/endpoints.go b/api/endpoints.go index 9185fb436..3d85be9af 100644 --- a/api/endpoints.go +++ b/api/endpoints.go @@ -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: @@ -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) diff --git a/block_test.go b/block_test.go index d0bbbfa56..0a4748490 100644 --- a/block_test.go +++ b/block_test.go @@ -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) diff --git a/builder/transaction_builder.go b/builder/transaction_builder.go index 0f8606ef2..7ec6d32b5 100644 --- a/builder/transaction_builder.go +++ b/builder/transaction_builder.go @@ -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 { diff --git a/builder/transaction_builder_test.go b/builder/transaction_builder_test.go index e4c2637ed..31cc0f552 100644 --- a/builder/transaction_builder_test.go +++ b/builder/transaction_builder_test.go @@ -1,4 +1,4 @@ -//nolint:scopelint +//nolint:scopelint,forcetypeassert package builder_test import ( @@ -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 @@ -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, } }(), @@ -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, } @@ -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", @@ -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{ @@ -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)", @@ -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)", diff --git a/feat_test.go b/feat_test.go index 704abfc5d..4a192c30e 100644 --- a/feat_test.go +++ b/feat_test.go @@ -428,6 +428,7 @@ func TestBlockIssuerFeatureSyntacticValidation(t *testing.T) { bik3, }), } + t.TransactionEssence.ContextInputs = append(t.TransactionEssence.ContextInputs, tpkg.RandCommitmentInput()) }, ), Target: &iotago.SignedTransaction{}, @@ -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, @@ -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, @@ -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, @@ -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, diff --git a/go.mod b/go.mod index 50e818cdc..4f9cd2ff4 100644 --- a/go.mod +++ b/go.mod @@ -4,16 +4,16 @@ go 1.22 require ( github.com/eclipse/paho.mqtt.golang v1.4.3 - github.com/ethereum/go-ethereum v1.13.12 + github.com/ethereum/go-ethereum v1.13.14 github.com/holiman/uint256 v1.2.4 - github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a - github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a + github.com/iotaledger/hive.go/constraints v0.0.0-20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/crypto v0.0.0-20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/ierrors v0.0.0-20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/lo v0.0.0-20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/runtime v0.0.0-20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240305162344-4b8be588e1cf + github.com/iotaledger/hive.go/stringify v0.0.0-20240305162344-4b8be588e1cf github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 github.com/pasztorpisti/qs v0.0.0-20171216220353-8d6c33ee906c github.com/samber/lo v1.39.0 @@ -30,7 +30,7 @@ require ( github.com/gorilla/websocket v1.5.1 // indirect github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect github.com/iancoleman/orderedmap v0.3.0 // indirect - github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a // indirect + github.com/iotaledger/hive.go/ds v0.0.0-20240305162344-4b8be588e1cf // indirect github.com/kr/text v0.2.0 // indirect github.com/mr-tron/base58 v1.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 9dbf42778..e0c6b3a02 100644 --- a/go.sum +++ b/go.sum @@ -13,8 +13,8 @@ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etly github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= github.com/eclipse/paho.mqtt.golang v1.4.3 h1:2kwcUGn8seMUfWndX0hGbvH8r7crgcJguQNCyp70xik= github.com/eclipse/paho.mqtt.golang v1.4.3/go.mod h1:CSYvoAlsMkhYOXh/oKyxa8EcBci6dVkLCbo5tTC1RIE= -github.com/ethereum/go-ethereum v1.13.12 h1:iDr9UM2JWkngBHGovRJEQn4Kor7mT4gt9rUZqB5M29Y= -github.com/ethereum/go-ethereum v1.13.12/go.mod h1:hKL2Qcj1OvStXNSEDbucexqnEt1Wh4Cz329XsjAalZY= +github.com/ethereum/go-ethereum v1.13.14 h1:EwiY3FZP94derMCIam1iW4HFVrSgIcpsu0HwTQtm6CQ= +github.com/ethereum/go-ethereum v1.13.14/go.mod h1:TN8ZiHrdJwSe8Cb6x+p0hs5CxhJZPbqB7hHkaUXcmIU= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= @@ -25,24 +25,24 @@ github.com/holiman/uint256 v1.2.4 h1:jUc4Nk8fm9jZabQuqr2JzednajVmBpC+oiTiXZJEApU github.com/holiman/uint256 v1.2.4/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= github.com/iancoleman/orderedmap v0.3.0 h1:5cbR2grmZR/DiVt+VJopEhtVs9YGInGIxAoMJn+Ichc= github.com/iancoleman/orderedmap v0.3.0/go.mod h1:XuLcCUkdL5owUCQeF2Ue9uuw1EptkJDkXXS7VoV7XGE= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a h1:9xeffzciYdw9L/ebAOPg/39Bqn3p5iyOROQhQHaAEUs= -github.com/iotaledger/hive.go/constraints v0.0.0-20240216135101-261e99d9d84a/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a h1:+l3NjL4v700Iv+ZF7KjPALkygFOxzkByoRIoSK9bOzc= -github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240216135101-261e99d9d84a/go.mod h1:9HM/YmzOfdlWXYHVEWVjYhKQHOlgxBVMsr5Vf5yn5IE= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a h1:ux81+J6mcxYw6usZpEPLZjE6J+TNs3RaRcTHa9+5ERM= -github.com/iotaledger/hive.go/crypto v0.0.0-20240216135101-261e99d9d84a/go.mod h1:7kZh98nwJInQsIybiPXSABc/on/IsDdXyeiPLfaH+2I= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a h1:7M1+k0H53jahg2ZDN10SociepCB+jymIZoiYaSenpbQ= -github.com/iotaledger/hive.go/ds v0.0.0-20240216135101-261e99d9d84a/go.mod h1:sE/HabIH9FWTvgaHioLN6o4rrxFMf4BuqRQwloxcamo= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a h1:ugcQ43xbMZo5XYTfanIHOxQGKNpxhcatcz9ZXcX6W1o= -github.com/iotaledger/hive.go/ierrors v0.0.0-20240216135101-261e99d9d84a/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a h1:eUAtyEIYRlAPeZ2qhlEA+7T8DVoYK2h9eotlst/84SU= -github.com/iotaledger/hive.go/lo v0.0.0-20240216135101-261e99d9d84a/go.mod h1:0ycE1W59kkNjQ87odL6H4x5Ik9bXhbNk88wmo+mIYt0= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a h1:qmfoYLK2XyPOXfldG21qHyCrbIf0sl7iJoFirvTrnO0= -github.com/iotaledger/hive.go/runtime v0.0.0-20240216135101-261e99d9d84a/go.mod h1:lAR3vbqE9g65M9VwWHiaXab2q+d89dBOFjhKgnDfK7c= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a h1:ahUFo0X9Th+8/aE6KSWiy7Eap5p0YFL6CDapP1o8dLo= -github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240216135101-261e99d9d84a/go.mod h1:yXQNGZUz++dB1T9RAHhWSresuTLzTC856ntdins9ivo= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a h1:xLreq/rXeSPdb86RnZNEPH3PUIWt56BQxK1+11+hM4I= -github.com/iotaledger/hive.go/stringify v0.0.0-20240216135101-261e99d9d84a/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= +github.com/iotaledger/hive.go/constraints v0.0.0-20240305162344-4b8be588e1cf h1:SHtB0Nf1MdOAk+adIQfQGWZ++EcvrfFE4kCTMbZ7Qys= +github.com/iotaledger/hive.go/constraints v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:JF7jjkL6tSUOXm23SWadBzBrl7eJk1DQRLc/fNoVZ+o= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240305162344-4b8be588e1cf h1:CxqQWH3cHX+jUx94zDeeCIe93gmygem1Y5jMrcAWJA4= +github.com/iotaledger/hive.go/core v1.0.0-rc.3.0.20240305162344-4b8be588e1cf/go.mod h1:73ODTHUJxAoGUN0InOtuQ29LVq85pDf7GckM9d0ziqo= +github.com/iotaledger/hive.go/crypto v0.0.0-20240305162344-4b8be588e1cf h1:msheCEl+Q1y8LQjfP9VOf6t38LeCOndhHkuw3AgMfK8= +github.com/iotaledger/hive.go/crypto v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:aREIB19gIhSYdY0Hl/37sg1JRH7+j3ajeJxBIQf6mig= +github.com/iotaledger/hive.go/ds v0.0.0-20240305162344-4b8be588e1cf h1:TyGz03gRMdFECQVc0gExs9W1k4lB10MPeRQohNilnmk= +github.com/iotaledger/hive.go/ds v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:wfjeJj9B+MM/3yeUHfvT8Gj8bRsdl9utyh2dZg+1+B0= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240305162344-4b8be588e1cf h1:aBMpx2sHnG7Esai4S7b47aUERBTV+JgoSjJKT1U4LxE= +github.com/iotaledger/hive.go/ierrors v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:GQY0/35sjgT9Poi1Vrs9kFVvAkuKzGXfVh4j6CBXsAA= +github.com/iotaledger/hive.go/lo v0.0.0-20240305162344-4b8be588e1cf h1:ADrQgsSpsoMSfIlSsMHo66ush8y0z8AaFn0Nae5dztY= +github.com/iotaledger/hive.go/lo v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:67oLzWYiBLGt5PN7IBVHdbt9P6oBYCx9UvMEL8ExDAc= +github.com/iotaledger/hive.go/runtime v0.0.0-20240305162344-4b8be588e1cf h1:gELL3pOfJADq6kLC6HkbEtFwAiVOm1cPuVy92noqjPk= +github.com/iotaledger/hive.go/runtime v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:pueoYXud+HmTY2x9j/S6+ZX3M5ZyENFKPDrx3EtcwWs= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240305162344-4b8be588e1cf h1:PAwjwceOCwCclmvCzbSJb0A7EolaDJsjWqw0ixRys0M= +github.com/iotaledger/hive.go/serializer/v2 v2.0.0-rc.1.0.20240305162344-4b8be588e1cf/go.mod h1:NK05G4PxwZF1m4jGANJWLhAQ2hP1Nt0L8mgCTFLsSCw= +github.com/iotaledger/hive.go/stringify v0.0.0-20240305162344-4b8be588e1cf h1:gLQTQtZZTwZBFZdx0tuM7WHpWtF1liC3c6FflZiNGXc= +github.com/iotaledger/hive.go/stringify v0.0.0-20240305162344-4b8be588e1cf/go.mod h1:O4p7UmsfoeLqtAUwrKbq0lXMxjY/MLQSpZSavvvvGig= github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7 h1:t6k4MqiUov0FrBb2o2JhKlOVSdlPbIQWM8ivYHL0G0g= github.com/iotaledger/iota-crypto-demo v0.0.0-20240216103559-27ca8dffd1e7/go.mod h1:do+N3LpeDEi9qselEC4XcjqGoRc7cWGiqBtIeBOKEMs= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= diff --git a/nodeclient/http_api_client.go b/nodeclient/http_api_client.go index 2eb02e021..ee9821b8f 100644 --- a/nodeclient/http_api_client.go +++ b/nodeclient/http_api_client.go @@ -255,6 +255,18 @@ func (client *Client) Info(ctx context.Context) (*api.InfoResponse, error) { return res, nil } +// NetworkMetrics gets the current network metrics. +func (client *Client) NetworkMetrics(ctx context.Context) (*api.NetworkMetricsResponse, error) { + res := new(api.NetworkMetricsResponse) + + //nolint:bodyclose + if _, err := do(ctx, iotago.CommonSerixAPI(), client.opts.httpClient, client.BaseURL, client.opts.userInfo, http.MethodGet, api.CoreRouteNetworkMetrics, client.opts.requestURLHook, nil, nil, res); err != nil { + return nil, err + } + + return res, nil +} + // BlockIssuance gets the info to issue a block. func (client *Client) BlockIssuance(ctx context.Context) (*api.IssuanceBlockHeaderResponse, error) { res := new(api.IssuanceBlockHeaderResponse) diff --git a/nodeclient/http_api_client_test.go b/nodeclient/http_api_client_test.go index aebab7654..5b0a090f5 100644 --- a/nodeclient/http_api_client_test.go +++ b/nodeclient/http_api_client_test.go @@ -132,11 +132,6 @@ func nodeClient(t *testing.T) *nodeclient.Client { Subunit: "testies", Decimals: 6, }, - Metrics: &api.InfoResNodeMetrics{ - BlocksPerSecond: 20.0, - ConfirmedBlocksPerSecond: 10.0, - ConfirmationRate: 50.0, - }, } mockGetJSON(api.CoreRouteInfo, 200, originInfo) @@ -147,6 +142,23 @@ func nodeClient(t *testing.T) *nodeclient.Client { return client } +func TestClient_NetworkMetrics(t *testing.T) { + defer gock.Off() + + originMetrics := &api.NetworkMetricsResponse{ + BlocksPerSecond: 20.0, + ConfirmedBlocksPerSecond: 10.0, + ConfirmationRate: 50.0, + } + + mockGetJSON(api.CoreRouteNetworkMetrics, 200, originMetrics) + + nodeAPI := nodeClient(t) + metrics, err := nodeAPI.NetworkMetrics(context.Background()) + require.NoError(t, err) + require.EqualValues(t, originMetrics, metrics) +} + func TestClient_Health(t *testing.T) { defer gock.Off() diff --git a/output.go b/output.go index 4bc34b9ea..bcfa016e6 100644 --- a/output.go +++ b/output.go @@ -886,3 +886,27 @@ func OutputsSyntacticalMetadataFeatureMaxSize() ElementValidationFunc[Output] { return nil } } + +// Checks that a Commitment Input is present for +// - Accounts with a Staking Feature. +// - Accounts with a Block Issuer Feature. +// - Delegation Outputs. +func OutputsSyntacticalCommitmentInput(hasCommitmentInput bool) ElementValidationFunc[Output] { + return func(index int, output Output) error { + hasStakingFeature := output.FeatureSet().Staking() != nil + if hasStakingFeature && !hasCommitmentInput { + return ierrors.Wrapf(ErrStakingCommitmentInputMissing, "output %d", index) + } + + hasBlockIssuerFeature := output.FeatureSet().BlockIssuer() != nil + if hasBlockIssuerFeature && !hasCommitmentInput { + return ierrors.Wrapf(ErrBlockIssuerCommitmentInputMissing, "output %d", index) + } + + if output.Type() == OutputDelegation && !hasCommitmentInput { + return ierrors.Wrapf(ErrDelegationCommitmentInputMissing, "output %d", index) + } + + return nil + } +} diff --git a/timeprovider.go b/timeprovider.go index aef507378..f460b4815 100644 --- a/timeprovider.go +++ b/timeprovider.go @@ -99,6 +99,11 @@ func (t *TimeProvider) SlotFromTime(targetTime time.Time) SlotIndex { return t.genesisSlot + SlotIndex(int64(elapsed/time.Second)/t.slotDurationSeconds) + 1 } +// CurrentSlot calculates the current slot based on the current time. +func (t *TimeProvider) CurrentSlot() SlotIndex { + return t.SlotFromTime(time.Now()) +} + // SlotStartTime calculates the start time of the given slot. func (t *TimeProvider) SlotStartTime(slot SlotIndex) time.Time { if slot <= t.genesisSlot { @@ -130,6 +135,11 @@ func (t *TimeProvider) EpochFromSlot(slot SlotIndex) EpochIndex { return EpochIndex((slot - t.genesisSlot) >> t.slotsPerEpochExponent) } +// CurrentEpoch calculates the current epoch based on the current time. +func (t *TimeProvider) CurrentEpoch() EpochIndex { + return t.EpochFromSlot(t.CurrentSlot()) +} + // EpochStart calculates the start slot of the given epoch. func (t *TimeProvider) EpochStart(epoch EpochIndex) SlotIndex { return t.genesisSlot + SlotIndex(epoch<