Skip to content

Commit

Permalink
feat(hip-869): added DAB Node operations
Browse files Browse the repository at this point in the history
  • Loading branch information
RickyLB authored Aug 27, 2024
1 parent 3c4de74 commit 346f855
Show file tree
Hide file tree
Showing 43 changed files with 3,418 additions and 28 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "3c54ab05249f59f2c6641dd2920b8358ea9ed127",
"version" : "1.24.0"
"revision" : "e17d61f26df0f0e06f58f6977ba05a097a720106",
"version" : "1.27.1"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ let package = Package(
.package(url: "https://github.com/objecthub/swift-numberkit.git", from: "2.4.1"),
.package(url: "https://github.com/thebarndog/swift-dotenv.git", from: "1.0.0"),
.package(url: "https://github.com/grpc/grpc-swift.git", from: "1.23.0"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.6.0"),
.package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"),
.package(url: "https://github.com/vsanthanam/AnyAsyncSequence.git", from: "1.0.0"),
.package(url: "https://github.com/apple/swift-atomics.git", from: "1.1.0"),
// swift-asn1 wants swift 5.7+ past 0.4
Expand Down
242 changes: 242 additions & 0 deletions Sources/Hedera/AddressBook/NodeCreateTransaction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,242 @@
/*
* ‌
* Hedera Swift SDK
* ​
* Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

import Foundation
import GRPC
import HederaProtobufs
import SwiftProtobuf

/// A transaction body to add a new consensus node to the network address book.
///
/// This transaction body SHALL be considered a "privileged transaction".
///
/// This message supports a transaction to create a new node in the network
/// address book. The transaction, once complete, enables a new consensus node
/// to join the network, and requires governing council authorization.
///
/// - A `NodeCreateTransactionBody` MUST be signed by the governing council.
/// - A `NodeCreateTransactionBody` MUST be signed by the `Key` assigned to the
/// `admin_key` field.
/// - The newly created node information SHALL be added to the network address
/// book information in the network state.
/// - The new entry SHALL be created in "state" but SHALL NOT participate in
/// network consensus and SHALL NOT be present in network "configuration"
/// until the next "upgrade" transaction (as noted below).
/// - All new address book entries SHALL be added to the active network
/// configuration during the next `freeze` transaction with the field
/// `freeze_type` set to `PREPARE_UPGRADE`.
///
public final class NodeCreateTransaction: Transaction {
public init(
accountId: AccountId? = nil,
description: String = "",
gossipEndpoints: [Endpoint] = [],
serviceEndpoints: [Endpoint] = [],
gossipCaCertificate: Data? = nil,
grpcCertificateHash: Data? = nil,
adminKey: Key? = nil
) {
self.accountId = accountId
self.description = description
self.gossipEndpoints = gossipEndpoints
self.serviceEndpoints = serviceEndpoints
self.gossipCaCertificate = gossipCaCertificate
self.grpcCertificateHash = grpcCertificateHash
self.adminKey = adminKey

super.init()
}

internal init(
protobuf proto: Proto_TransactionBody, _ data: Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody
) throws {
self.accountId = data.hasAccountID ? try .fromProtobuf(data.accountID) : nil
self.description = data.description_p
self.gossipEndpoints = try data.gossipEndpoint.map(Endpoint.init)
self.serviceEndpoints = try data.serviceEndpoint.map(Endpoint.init)
self.gossipCaCertificate = data.gossipCaCertificate
self.grpcCertificateHash = data.grpcCertificateHash
self.adminKey = data.hasAdminKey ? try .fromProtobuf(data.adminKey) : nil

try super.init(protobuf: proto)
}

/// Node account ID.
public var accountId: AccountId? {
willSet {
ensureNotFrozen()
}
}

/// Sets the node account
@discardableResult
public func accountId(_ accountId: AccountId?) -> Self {
self.accountId = accountId

return self
}

/// Returns the nodes description.
public var description: String {
willSet {
ensureNotFrozen()
}
}

/// Sets the node's description.
@discardableResult
public func description(_ description: String) -> Self {
self.description = description

return self
}

/// A list of service endpoints for gossip.
public var gossipEndpoints: [Endpoint] {
willSet {
ensureNotFrozen()
}
}

/// Assign the list of service endpoints for gossip.
@discardableResult
public func gossipEndpoints(_ gossipEndpoints: [Endpoint]) -> Self {
self.gossipEndpoints = gossipEndpoints

return self
}

/// Add an endpoint for gossip to the list of service endpoints for gossip.
@discardableResult
public func addGossipEndpoint(_ gossipEndpoint: Endpoint) -> Self {
self.gossipEndpoints.append(gossipEndpoint)

return self
}

/// Extract the list of service endpoints for gRPC calls.
public var serviceEndpoints: [Endpoint] {
willSet {
ensureNotFrozen()
}
}

/// Assign the list of service endpoints for gRPC calls.
@discardableResult
public func serviceEndpoints(_ serviceEndpoints: [Endpoint]) -> Self {
self.serviceEndpoints = serviceEndpoints

return self
}

/// Add an endpoint for gRPC calls to the list of service endpoints for gRPC calls.
@discardableResult
public func addServiceEndpoint(_ serviceEndpoint: Endpoint) -> Self {
self.serviceEndpoints.append(serviceEndpoint)

return self
}

/// Extract the certificate used to sign gossip events.
public var gossipCaCertificate: Data? {
willSet {
ensureNotFrozen()
}
}

/// Sets the certificate used to sign gossip events.
@discardableResult
public func gossipCaCertificate(_ gossipCaCertificate: Data) -> Self {
self.gossipCaCertificate = gossipCaCertificate

return self
}

/// Extract the hash of the node gRPC TLS certificate.
public var grpcCertificateHash: Data? {
willSet {
ensureNotFrozen()
}
}

/// Sets the hash of the node gRPC TLS certificate.
@discardableResult
public func grpcCertificateHash(_ grpcCertificateHash: Data) -> Self {
self.grpcCertificateHash = grpcCertificateHash

return self
}

/// Get an administrative key controlled by the node operator.
public var adminKey: Key? {
willSet {
ensureNotFrozen()
}
}

/// Sets an administrative key controlled by the node operator.
@discardableResult
public func adminKey(_ adminKey: Key) -> Self {
self.adminKey = adminKey

return self
}

internal override func validateChecksums(on ledgerId: LedgerId) throws {
try accountId?.validateChecksums(on: ledgerId)
try super.validateChecksums(on: ledgerId)
}

internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws
-> Proto_TransactionResponse
{
try await Proto_AddressBookServiceAsyncClient(channel: channel).createNode(request)
}

internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data {
_ = chunkInfo.assertSingleTransaction()

return .nodeCreate(toProtobuf())
}
}

extension NodeCreateTransaction: ToProtobuf {
internal typealias Protobuf = Com_Hedera_Hapi_Node_Addressbook_NodeCreateTransactionBody

internal func toProtobuf() -> Protobuf {
.with { proto in
accountId?.toProtobufInto(&proto.accountID)
proto.description_p = description
proto.gossipEndpoint = gossipEndpoints.map { $0.toProtobuf() }
proto.serviceEndpoint = serviceEndpoints.map { $0.toProtobuf() }
proto.gossipCaCertificate = gossipCaCertificate ?? Data()
proto.grpcCertificateHash = grpcCertificateHash ?? Data()
if let adminKey = adminKey {
proto.adminKey = adminKey.toProtobuf()
}
}
}
}

extension NodeCreateTransaction {
internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data {
.nodeCreate(toProtobuf())
}
}
98 changes: 98 additions & 0 deletions Sources/Hedera/AddressBook/NodeDeleteTransaction.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* ‌
* Hedera Swift SDK
* ​
* Copyright (C) 2022 - 2024 Hedera Hashgraph, LLC
* ​
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ‍
*/

import Foundation
import GRPC
import HederaProtobufs
import SwiftProtobuf

/// A transaction body to delete a node from the network address book.
///
/// This transaction body SHALL be considered a "privileged transaction".
///
/// - A `NodeDeleteTransactionBody` MUST be signed by the governing council.
/// - Upon success, the address book entry SHALL enter a "pending delete"
/// state.
/// - All address book entries pending deletion SHALL be removed from the
/// active network configuration during the next `freeze` transaction with
/// the field `freeze_type` set to `PREPARE_UPGRADE`.<br/>
/// - A deleted address book node SHALL be removed entirely from network state.
/// - A deleted address book node identifier SHALL NOT be reused.
public final class NodeDeleteTransaction: Transaction {
public init(
nodeId: UInt64 = 0
) {
self.nodeId = nodeId
super.init()
}

internal init(
protobuf proto: Proto_TransactionBody, _ data: Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody
) throws {
self.nodeId = data.nodeID

try super.init(protobuf: proto)
}

/// Node index to delete.
public var nodeId: UInt64 {
willSet {
ensureNotFrozen()
}
}

/// Sets the node index to delete.
@discardableResult
public func nodeId(_ nodeId: UInt64) -> Self {
self.nodeId = nodeId

return self
}

internal override func validateChecksums(on ledgerId: LedgerId) throws {}

internal override func transactionExecute(_ channel: GRPCChannel, _ request: Proto_Transaction) async throws
-> Proto_TransactionResponse
{
try await Proto_AddressBookServiceAsyncClient(channel: channel).deleteNode(request)
}

internal override func toTransactionDataProtobuf(_ chunkInfo: ChunkInfo) -> Proto_TransactionBody.OneOf_Data {
_ = chunkInfo.assertSingleTransaction()

return .nodeDelete(toProtobuf())
}
}

extension NodeDeleteTransaction: ToProtobuf {
internal typealias Protobuf = Com_Hedera_Hapi_Node_Addressbook_NodeDeleteTransactionBody

internal func toProtobuf() -> Protobuf {
.with { proto in
proto.nodeID = nodeId
}
}
}

extension NodeDeleteTransaction {
internal func toSchedulableTransactionData() -> Proto_SchedulableTransactionBody.OneOf_Data {
.nodeDelete(toProtobuf())
}
}
Loading

0 comments on commit 346f855

Please sign in to comment.