Skip to content
Closed
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
39 changes: 31 additions & 8 deletions sdk/endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import (
"fmt"

"github.com/hiero-ledger/hiero-sdk-go/v2/proto/services"
"github.com/pkg/errors"
)

type Endpoint struct {
address []byte
port int32
domainName string
domainName *string
}

func (endpoint *Endpoint) SetAddress(address []byte) *Endpoint {
Expand All @@ -33,12 +34,25 @@ func (endpoint *Endpoint) GetPort() int32 {
}

func (endpoint *Endpoint) SetDomainName(domainName string) *Endpoint {
endpoint.domainName = domainName
endpoint.domainName = &domainName
return endpoint
}

func (endpoint *Endpoint) GetDomainName() string {
return endpoint.domainName
if endpoint.domainName != nil {
return *endpoint.domainName
}
return ""
}

func (endpoint *Endpoint) Validate() error {
if endpoint.address == nil && endpoint.domainName == nil {
return errors.New("endpoint must have either address or domain name")
}
if endpoint.address != nil && endpoint.domainName != nil {
return errors.New("endpoint must have either address or domain name")
}
return nil
}

func EndpointFromProtobuf(serviceEndpoint *services.ServiceEndpoint) Endpoint {
Expand All @@ -48,25 +62,34 @@ func EndpointFromProtobuf(serviceEndpoint *services.ServiceEndpoint) Endpoint {
port = 50211
}

var domainName *string
if serviceEndpoint.GetDomainName() != "" {
domainName = &serviceEndpoint.DomainName
}

return Endpoint{
address: serviceEndpoint.GetIpAddressV4(),
port: port,
domainName: serviceEndpoint.GetDomainName(),
domainName: domainName,
}
}

func (endpoint *Endpoint) _ToProtobuf() *services.ServiceEndpoint {
return &services.ServiceEndpoint{
body := &services.ServiceEndpoint{
IpAddressV4: endpoint.address,
Port: endpoint.port,
DomainName: endpoint.domainName,
}

if endpoint.domainName != nil {
body.DomainName = *endpoint.domainName
}
return body
}

func (endpoint *Endpoint) String() string {
if endpoint.domainName != "" {
if endpoint.domainName != nil {
// If domain name is populated domainName + port
return endpoint.domainName + ":" + fmt.Sprintf("%d", endpoint.port)
return *endpoint.domainName + ":" + fmt.Sprintf("%d", endpoint.port)
} else {
return fmt.Sprintf("%d.%d.%d.%d:%d",
int(endpoint.address[0])&0xFF,
Expand Down
4 changes: 3 additions & 1 deletion sdk/node_address_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func TestUnitNodeAddressStringTest(t *testing.T) {
id, err := AccountIDFromString("0.0.123")
require.NoError(t, err)

domainName := "example.com"

// Prepare a NodeAddress struct for testing
nodeAddress := NodeAddress{
PublicKey: "sample-public-key",
Expand All @@ -28,7 +30,7 @@ func TestUnitNodeAddressStringTest(t *testing.T) {
{
address: []byte("192.168.1.1"),
port: 8080,
domainName: "example.com",
domainName: &domainName,
},
},
Description: "Sample Node",
Expand Down
67 changes: 62 additions & 5 deletions sdk/node_create_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"github.com/hiero-ledger/hiero-sdk-go/v2/proto/services"
"github.com/pkg/errors"
)

// SPDX-License-Identifier: Apache-2.0
Expand Down Expand Up @@ -36,7 +37,7 @@
description string
gossipEndpoints []Endpoint
serviceEndpoints []Endpoint
gossipCaCertificate []byte
gossipCaCertificate *[]byte
grpcCertificateHash []byte
adminKey Key
declineReward *bool
Expand Down Expand Up @@ -73,13 +74,14 @@
}

declineReward := pb.GetNodeCreate().GetDeclineReward()
gossipCaCertificate := pb.GetNodeCreate().GetGossipCaCertificate()

nodeCreateTransaction := NodeCreateTransaction{
accountID: accountID,
description: pb.GetNodeCreate().GetDescription(),
gossipEndpoints: gossipEndpoints,
serviceEndpoints: serviceEndpoints,
gossipCaCertificate: pb.GetNodeCreate().GetGossipCaCertificate(),
gossipCaCertificate: &gossipCaCertificate,
grpcCertificateHash: pb.GetNodeCreate().GetGrpcCertificateHash(),
adminKey: adminKey,
declineReward: &declineReward,
Expand Down Expand Up @@ -153,20 +155,27 @@
// AddServiceEndpoint the list of service endpoints for gRPC calls.
func (tx *NodeCreateTransaction) AddServiceEndpoint(endpoint Endpoint) *NodeCreateTransaction {
tx._RequireNotFrozen()
if err := endpoint.Validate(); err != nil {
tx.freezeError = err
return tx
}
tx.serviceEndpoints = append(tx.serviceEndpoints, endpoint)
return tx
}

// GetGossipCaCertificate the certificate used to sign gossip events.
func (tx *NodeCreateTransaction) GetGossipCaCertificate() []byte {
return tx.gossipCaCertificate
if tx.gossipCaCertificate == nil {
return []byte{}
}
return *tx.gossipCaCertificate
}

// SetGossipCaCertificate the certificate used to sign gossip events.
// This value MUST be the DER encoding of the certificate presented.
func (tx *NodeCreateTransaction) SetGossipCaCertificate(gossipCaCertificate []byte) *NodeCreateTransaction {
tx._RequireNotFrozen()
tx.gossipCaCertificate = gossipCaCertificate
tx.gossipCaCertificate = &gossipCaCertificate
return tx
}

Expand Down Expand Up @@ -283,7 +292,7 @@
}

if tx.gossipCaCertificate != nil {
body.GossipCaCertificate = tx.gossipCaCertificate
body.GossipCaCertificate = *tx.gossipCaCertificate
}

if tx.grpcCertificateHash != nil {
Expand All @@ -307,6 +316,54 @@
}
}

func (tx NodeCreateTransaction) preFreezeWith(client *Client, self TransactionInterface) {

Check failure on line 319 in sdk/node_create_transaction.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sdk/node_create_transaction.go#L319

Method preFreezeWith has a cyclomatic complexity of 19 (limit is 12)
if tx.gossipEndpoints != nil {
if len(tx.gossipEndpoints) > 10 {
tx.freezeError = errors.New("gossip endpoints must not contain more than 10 entries")
return
}
for _, endpoint := range tx.gossipEndpoints {
if err := endpoint.Validate(); err != nil {
tx.freezeError = err
return
}
}
}

if tx.serviceEndpoints != nil {
if len(tx.serviceEndpoints) > 8 {
tx.freezeError = errors.New("service endpoints must not contain more than 10 entries")
return
}
for _, endpoint := range tx.serviceEndpoints {
if err := endpoint.Validate(); err != nil {
tx.freezeError = err
return
}
}
}

if tx.grpcWebProxyEndpoint != nil {
if err := tx.grpcWebProxyEndpoint.Validate(); err != nil {
tx.freezeError = err
return
}
}

if tx.gossipCaCertificate != nil {
if len(*tx.gossipCaCertificate) == 0 {
tx.freezeError = errors.New("gossip ca certificate must not be empty")
return
}
}

if tx.description != "" {
if len(tx.description) > 100 {
tx.freezeError = errors.New("description must be less than 100 characters")
}
}
}

func (tx NodeCreateTransaction) constructScheduleProtobuf() (*services.SchedulableTransactionBody, error) {
return tx.buildScheduled()
}
Expand Down
9 changes: 5 additions & 4 deletions sdk/node_create_transaction_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,19 @@ func TestIntegrationNodeCreateTransactionCanExecute(t *testing.T) {
// Node description
description := "test"

domainName := "test.com"

// Endpoint address can be any IPV4 address
endpoint := Endpoint{
domainName: "tset.com",
domainName: &domainName,
port: 123,
}

endpoint1 := Endpoint{
domainName: "test.com",
domainName: &domainName,
port: 1234,
}

// DER encoded x509 certificate
validGossipCertDER := "3082052830820310a003020102020101300d06092a864886f70d01010c05003010310e300c060355040313056e6f6465333024170d3234313030383134333233395a181332313234313030383134333233392e3337395a3010310e300c060355040313056e6f64653330820222300d06092a864886f70d01010105000382020f003082020a0282020100af111cff0c4ad8125d2f4b8691ce87332fecc867f7a94ddc0f3f96514cc4224d44af516394f7384c1ef0a515d29aa6116b65bc7e4d7e2d848cf79fbfffedae3a6583b3957a438bdd780c4981b800676ea509bc8c619ae04093b5fc642c4484152f0e8bcaabf19eae025b630028d183a2f47caf6d9f1075efb30a4248679d871beef1b7e9115382270cbdb68682fae4b1fd592cadb414d918c0a8c23795c7c5a91e22b3e90c410825a2bc1a840efc5bf9976a7f474c7ed7dc047e4ddd2db631b68bb4475f173baa3edc234c4bed79c83e2f826f79e07d0aade2d984da447a8514135bfa4145274a7f62959a23c4f0fae5adc6855974e7c04164951d052beb5d45cb1f3cdfd005da894dea9151cb62ba43f4731c6bb0c83e10fd842763ba6844ef499f71bc67fa13e4917fb39f2ad18112170d31cdcb3c61c9e3253accf703dbd8427fdcb87ece78b787b6cfdc091e8fedea8ad95dc64074e1fc6d0e42ea2337e18a5e54e4aaab3791a98dfcef282e2ae1caec9cf986fabe8f36e6a21c8711647177e492d264415e765a86c58599cd97b103cb4f6a01d2edd06e3b60470cf64daca7aecf831197b466cae04baeeac19840a05394bef628aed04b611cfa13677724b08ddfd662b02fd0ef0af17eb7f4fb8c1c17fbe9324f6dc7bcc02449622636cc45ec04909b3120ab4df4726b21bf79e955fe8f832699d2196dcd7a58bfeafb170203010001a38186308183300f0603551d130101ff04053003020100300e0603551d0f0101ff0404030204b030200603551d250101ff0416301406082b0601050507030106082b06010505070302301d0603551d0e04160414643118e05209035edd83d44a0c368de2fb2fe4c0301f0603551d23041830168014643118e05209035edd83d44a0c368de2fb2fe4c0300d06092a864886f70d01010c05000382020100ad41c32bb52650eb4b76fce439c9404e84e4538a94916b3dc7983e8b5c58890556e7384601ca7440dde68233bb07b97bf879b64487b447df510897d2a0a4e789c409a9b237a6ad240ad5464f2ce80c58ddc4d07a29a74eb25e1223db6c00e334d7a27d32bfa6183a82f5e35bccf497c2445a526eabb0c068aba9b94cc092ea4756b0dcfb574f6179f0089e52b174ccdbd04123eeb6d70daeabd8513fcba6be0bc2b45ca9a69802dae11cc4d9ff6053b3a87fd8b0c6bf72fffc3b81167f73cca2b3fd656c5d353c8defca8a76e2ad535f984870a590af4e28fed5c5a125bf360747c5e7742e7813d1bd39b5498c8eb6ba72f267eda034314fdbc596f6b967a0ef8be5231d364e634444c84e64bd7919425171016fcd9bb05f01c58a303dee28241f6e860fc3aac3d92aad7dac2801ce79a3b41a0e1f1509fc0d86e96d94edb18616c000152490f64561713102128990fedd3a5fa642f2ff22dc11bc4dc5b209986a0c3e4eb2bdfdd40e9fdf246f702441cac058dd8d0d51eb0796e2bea2ce1b37b2a2f468505e1f8980a9f66d719df034a6fbbd2f9585991d259678fb9a4aebdc465d22c240351ed44abffbdd11b79a706fdf7c40158d3da87f68d7bd557191a8016b5b899c07bf1b87590feb4fa4203feea9a2a7a73ec224813a12b7a21e5dc93fcde4f0a7620f570d31fe27e9b8d65b74db7dc18a5e51adc42d7805d4661938"

// Convert hex string to byte array
Expand All @@ -58,7 +59,7 @@ func TestIntegrationNodeCreateTransactionCanExecute(t *testing.T) {
require.NoError(t, err)

grpcProxyEndpoint := Endpoint{
domainName: "testWeb.com",
domainName: &domainName,
port: 12345,
}

Expand Down
69 changes: 62 additions & 7 deletions sdk/node_update_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"github.com/hiero-ledger/hiero-sdk-go/v2/proto/services"
"github.com/pkg/errors"

"google.golang.org/protobuf/types/known/wrapperspb"
)
Expand Down Expand Up @@ -35,7 +36,7 @@
description string
gossipEndpoints []Endpoint
serviceEndpoints []Endpoint
gossipCaCertificate []byte
gossipCaCertificate *[]byte
grpcCertificateHash []byte
adminKey Key
declineReward *bool
Expand Down Expand Up @@ -99,7 +100,7 @@
description: description,
gossipEndpoints: gossipEndpoints,
serviceEndpoints: serviceEndpoints,
gossipCaCertificate: certificate,
gossipCaCertificate: &certificate,
grpcCertificateHash: certificateHash,
adminKey: adminKey,
grpcWebProxyEndpoint: grpcProxyEndpoint,
Expand Down Expand Up @@ -201,14 +202,17 @@

// GetGossipCaCertificate the certificate used to sign gossip events.
func (tx *NodeUpdateTransaction) GetGossipCaCertificate() []byte {
return tx.gossipCaCertificate
if tx.gossipCaCertificate == nil {
return []byte{}
}
return *tx.gossipCaCertificate
}

// SetGossipCaCertificate the certificate used to sign gossip events.
// This value MUST be the DER encoding of the certificate presented.
func (tx *NodeUpdateTransaction) SetGossipCaCertificate(gossipCaCertificate []byte) *NodeUpdateTransaction {
tx._RequireNotFrozen()
tx.gossipCaCertificate = gossipCaCertificate
tx.gossipCaCertificate = &gossipCaCertificate
return tx
}

Expand Down Expand Up @@ -321,8 +325,6 @@

if tx.nodeID != nil {
body.NodeId = *tx.nodeID
} else {
tx.freezeError = errNodeIdIsRequired
}

if tx.accountID != nil {
Expand All @@ -342,7 +344,7 @@
}

if tx.gossipCaCertificate != nil {
body.GossipCaCertificate = wrapperspb.Bytes(tx.gossipCaCertificate)
body.GossipCaCertificate = wrapperspb.Bytes(*tx.gossipCaCertificate)
}

if tx.grpcCertificateHash != nil {
Expand All @@ -360,6 +362,59 @@
return body
}

func (tx NodeUpdateTransaction) preFreezeWith(client *Client, self TransactionInterface) {

Check failure on line 365 in sdk/node_update_transaction.go

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

sdk/node_update_transaction.go#L365

Method preFreezeWith has a cyclomatic complexity of 14 (limit is 12)
if tx.gossipEndpoints != nil {
if len(tx.gossipEndpoints) > 10 {
tx.freezeError = errors.New("gossip endpoints must not contain more than 10 entries")
return
}
for _, endpoint := range tx.gossipEndpoints {
if err := endpoint.Validate(); err != nil {
tx.freezeError = err
return
}
}
}

if tx.serviceEndpoints != nil {
if len(tx.serviceEndpoints) > 8 {
tx.freezeError = errors.New("service endpoints must not contain more than 10 entries")
return
}
for _, endpoint := range tx.serviceEndpoints {
if err := endpoint.Validate(); err != nil {
tx.freezeError = err
return
}
}
}

// if tx.grpcWebProxyEndpoint != nil {
// if err := tx.grpcWebProxyEndpoint.Validate(); err != nil {
// tx.freezeError = err
// return
// }
// }

if tx.gossipCaCertificate != nil {
if len(*tx.gossipCaCertificate) == 0 {
tx.freezeError = errors.New("gossip ca certificate must not be empty")
return
}
}

if tx.description != "" {
if len(tx.description) > 100 {
tx.freezeError = errors.New("description must be less than 100 characters")
return
}
}

if tx.nodeID == nil {
tx.freezeError = errNodeIdIsRequired
}
}

func (tx NodeUpdateTransaction) getMethod(channel *_Channel) _Method {
return _Method{
transaction: channel._GetAddressBook().UpdateNode,
Expand Down
4 changes: 3 additions & 1 deletion sdk/node_update_transaction_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ func TestIntegrationNodeUpdateTransactionCanExecute(t *testing.T) {
require.NoError(t, err)
client.SetOperator(AccountID{Account: 2}, originalOperatorKey)

domainName := "testWebUpdated.com"

resp, err := NewNodeUpdateTransaction().
SetNodeID(0).
SetDescription("testUpdated").
SetDeclineReward(true).
SetGrpcWebProxyEndpoint(Endpoint{
domainName: "testWebUpdated.com",
domainName: &domainName,
port: 123456,
}).
Execute(client)
Expand Down
Loading
Loading