Help with fixing high memory usage in proof of work blockchain code

I need some insights into what is using memory while the program mines a transaction in this code

import Foundation

import CryptoKit

struct Blockchain {
  private var difficulty: Int
  var chain: [Transaction]

  init(_ difficulty: Int) {
    self.difficulty = difficulty
    chain = []
  }

  func isValidChain() -> Bool {
    var prevHash: String? = nil

    for transaction in chain {
      let metadata = transaction.metadata

      if transaction.id != 0 {
        if metadata.prevHash != prevHash {
          return false
        }
      }

      if let derSignature = transaction.senderSignature {
        if let signature = try? P256.Signing.ECDSASignature(derRepresentation: derSignature),
           let publicKey = try? P256.Signing.PublicKey(derRepresentation: metadata.from),
           let encoded   = try? JSONEncoder().encode(metadata) {
          if !publicKey.isValidSignature(signature, for: encoded){
            return false
          }
        } else {
          return false
        }
      } else {
        return false
      }

      prevHash = calculateHash(transaction)

      if let hash = prevHash {
        if !hash.hasPrefix(String(repeating: "0", count: difficulty)) {
          return false
        }
      }
    }

    return true
  }

  mutating func createTransaction(
    to: Data,
    privateKey: P256.Signing.PrivateKey,
    value: Double
  ) {
    var prevHash: String? = nil
    if let prevTransaction = chain.last {
      prevHash = calculateHash(prevTransaction)
    }

    let metadata = Transaction.Metadata(
      prevHash: prevHash,
      from: privateKey.publicKey.derRepresentation,
      to: to,
      value: value
    )

    var transaction = Transaction(
      id: chain.count,
      metadata: metadata,
      senderSignature: calculateSignature(metadata, privateKey: privateKey)
    )

    var hash = calculateHash(transaction)
    while true {
      if let validHash = hash {
        if validHash.hasPrefix(String(repeating: "0", count: difficulty)) {
          break
        } else {
          transaction.nonce += 1
          hash = calculateHash(transaction)
        }
      } else {
        return
      }
    }
    
chain.append(transaction)
  }

  private func calculateHash(_ transaction: Transaction) -> String? {
    if let encoded = try? JSONEncoder().encode(transaction) {
      return SHA256.hash(data: encoded).compactMap {
        String(format: "%02x", $0)
      }.joined()
    }
    return nil
  }

  private func calculateSignature(
    _ metadata: Transaction.Metadata,
    privateKey: P256.Signing.PrivateKey
  ) -> Data? {
    if let encoded = try? JSONEncoder().encode(metadata) {
      return try? privateKey.signature(for: encoded).derRepresentation
    }
    return nil
  }

  struct Transaction: Codable, Identifiable {
    var id: Int
    var metadata: Metadata
    var senderSignature: Data?
    var nonce = 0

    struct Metadata: Codable {
      var prevHash: String?
      var from: Data
      var to: Data
      var value: Double
    }
  }
}

#if DEBUG

var blockchain = Blockchain(4)

let privateKey1 = P256.Signing.PrivateKey.init(compactRepresentable: false)
let publicKey1  = privateKey1.publicKey

let privateKey2 = P256.Signing.PrivateKey.init(compactRepresentable: false)
let publicKey2  = privateKey2.publicKey

blockchain.createTransaction(
  to: publicKey2.derRepresentation,
  privateKey: privateKey1,
  value: 0
)

blockchain.createTransaction(
  to: publicKey1.derRepresentation,
  privateKey: privateKey2,
  value: 0
)

var output = "["
for transaction in blockchain.chain {
  if let encoded = try? JSONEncoder().encode(transaction) {
    output += String(data: encoded, encoding: .utf8)! + ","
  }
}
let _ = output.popLast()
output += "]"
print(output)
print(blockchain.isValidChain())

while true {
  sleep(1000)
}
#endif
Accepted Answer

I needed to wrap the code in the while loop with autoreleasepool

    let prefix = String(repeating: "0", count: difficulty)
    var hash = calculateHash(transaction)
    while !hash!.hasPrefix(prefix) {
      autoreleasepool {
        transaction.nonce += 1
        hash = calculateHash(transaction)
      }
    }
Help with fixing high memory usage in proof of work blockchain code
 
 
Q