talexm commited on
Commit
92c34be
1 Parent(s): fdc732d

adding chinguard, anomaly detector and visualisation tool

Browse files
anomaly_detection_tool/README.md ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Anomaly Detection Model
2
+ ## Overview
3
+ This repository contains a Python class AnomalyDetectionModel built using TensorFlow and Keras
4
+ for detecting anomalies in network traffic data. The class encapsulates the creation, training,
5
+ and evaluation of a neural network model designed to classify network data as either normal or anomalous.
6
+
7
+ ### Why Use a Sequential Model?
8
+ The Sequential model in Keras is a simple, linear stack of layers.
9
+ It is ideal for building feedforward neural networks where the model
10
+ progresses through each layer sequentially, without any branching or complex topologies.
11
+
12
+ ### Key Reasons for Using Sequential:
13
+
14
+ Simplicity: The Sequential API is straightforward and easy to use. It is perfect for beginners and
15
+ for models that involve a single input and output with layers stacked one after the other.
16
+
17
+ Linear Stack: For the task of anomaly detection, the architecture typically involves a simple
18
+ forward pass through several dense layers, making the Sequential model a natural fit.
19
+
20
+ Flexibility: While simple, the Sequential model is flexible enough to allow for customization
21
+ through the addition of various types of layers, activation functions, and regularization techniques.
22
+
23
+ Example Usage
24
+ ```python
25
+
26
+ # Initialize the model with the input shape
27
+ anomaly_model = AnomalyDetectionModel(X_train.shape[1])
28
+
29
+ # Train the model
30
+ history = anomaly_model.train(X_train, y_train)
31
+
32
+ # Evaluate the model on the test data
33
+ loss, accuracy = anomaly_model.evaluate(X_test, y_test)
34
+ print(f'Test Accuracy: {accuracy:.4f}')
35
+ ```
36
+
37
+ Dependencies
38
+ Python 3.x
39
+ TensorFlow
40
+ Keras (included with TensorFlow)
41
+ Scikit-learn
42
+ Pandas
43
+ Installation
44
+ Install the required packages using pip:
45
+
46
+ Conclusion
47
+ The Sequential model is a great choice for this anomaly detection task due to its simplicity,
48
+ ease of use, and the linear nature of the problem. This approach ensures that the model is easy
49
+ to build, understand, and maintain while still providing robust performance for binary classification
50
+ tasks such as anomaly detection.
{sec-rag-model → anomaly_detection_tool}/__init__.py RENAMED
File without changes
anomaly_detection_tool/anomaly_detection_model.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ from tensorflow.keras import layers, models
3
+
4
+ class AnomalyDetectionModel:
5
+ def __init__(self, input_shape):
6
+ self.model = self.build_model(input_shape)
7
+
8
+ def build_model(self, input_shape):
9
+ model = models.Sequential([
10
+ layers.Dense(64, activation='relu', input_shape=(input_shape,)),
11
+ layers.Dense(32, activation='relu'),
12
+ layers.Dense(16, activation='relu'),
13
+ layers.Dense(1, activation='sigmoid')
14
+ ])
15
+ model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
16
+ return model
17
+
18
+ def train(self, X_train, y_train, epochs=10, batch_size=32, validation_split=0.2):
19
+ history = self.model.fit(X_train, y_train, epochs=epochs, batch_size=batch_size, validation_split=validation_split)
20
+ return history
21
+
22
+ def evaluate(self, X_test, y_test):
23
+ loss, accuracy = self.model.evaluate(X_test, y_test)
24
+ return loss, accuracy
25
+
26
+ # Example usage:
27
+ # anomaly_model = AnomalyDetectionModel(X_train.shape[1])
28
+ # history = anomaly_model.train(X_train, y_train)
29
+ # loss, accuracy = anomaly_model.evaluate(X_test, y_test)
30
+ # print(f'Test Accuracy: {accuracy:.4f}')
anomaly_detection_tool/data_processor.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #import fireducks.pandas as pd
2
+ import pandas as pd
3
+
4
+ from sklearn.model_selection import train_test_split
5
+ from sklearn.preprocessing import LabelEncoder, StandardScaler
6
+
7
+ class DataProcessor:
8
+ def __init__(self, csv_file):
9
+ self.data = pd.read_csv(csv_file)
10
+ self.label_encoders = {}
11
+ self.scaler = StandardScaler()
12
+
13
+ def preprocess_data(self):
14
+ for column in ['IP', 'Hostnames', 'OS']:
15
+ self.label_encoders[column] = LabelEncoder()
16
+ self.data[column] = self.label_encoders[column].fit_transform(self.data[column].astype(str))
17
+
18
+ self.data['Port'] = self.scaler.fit_transform(self.data[['Port']])
19
+ self.data['Timestamp'] = pd.to_datetime(self.data['Timestamp']).astype(int) / 10**9
20
+ return self.data
21
+
22
+ def get_features_and_labels(self, label_column='Anomaly'):
23
+ if label_column not in self.data.columns:
24
+ raise ValueError(f"Label column '{label_column}' not found in data.")
25
+
26
+ X = self.data.drop([label_column], axis=1)
27
+ y = self.data[label_column]
28
+ return X, y
29
+
30
+ def split_data(self, X, y, test_size=0.2, random_state=42):
31
+ X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size, random_state=random_state)
32
+ return X_train, X_test, y_train, y_test
33
+
34
+ # # Example usage:
35
+ # processor = DataProcessor('shodan_scan_results.csv')
36
+ # processed_data = processor.preprocess_data()
37
+ # X, y = processor.get_features_and_labels()
38
+ # X_train, X_test, y_train, y_test = processor.split_data(X, y)
chainguard/__init__.py ADDED
File without changes
chainguard/blockchain.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import hashlib
2
+ import time
3
+
4
+ class Block:
5
+ def __init__(self, index, previous_hash, timestamp, data, hash):
6
+ self.index = index
7
+ self.previous_hash = previous_hash
8
+ self.timestamp = timestamp
9
+ self.data = data
10
+ self.hash = hash
11
+
12
+ class Blockchain:
13
+ def __init__(self):
14
+ self.chain = [self.create_genesis_block()]
15
+
16
+ def create_genesis_block(self):
17
+ genesis_block = Block(0, "0", int(time.time()), "Genesis Block", "0")
18
+ genesis_block.hash = self.calculate_hash(genesis_block)
19
+ return genesis_block
20
+
21
+ def calculate_hash(self, block):
22
+ block_string = f"{block.index}{block.previous_hash}{block.timestamp}{block.data}".encode()
23
+ return hashlib.sha256(block_string).hexdigest()
24
+
25
+ def get_latest_block(self):
26
+ return self.chain[-1]
27
+
28
+ def add_block(self, data):
29
+ latest_block = self.get_latest_block()
30
+ new_block = Block(len(self.chain), latest_block.hash, int(time.time()), data, "")
31
+ new_block.hash = self.calculate_hash(new_block)
32
+ self.chain.append(new_block)
33
+ print(f"Block added: {new_block.hash}")
34
+ return new_block
35
+
36
+ def is_chain_valid(self):
37
+ for i in range(1, len(self.chain)):
38
+ current_block = self.chain[i]
39
+ previous_block = self.chain[i - 1]
40
+
41
+ if current_block.hash != self.calculate_hash(current_block):
42
+ return False
43
+
44
+ if current_block.previous_hash != previous_block.hash:
45
+ return False
46
+ return True
chainguard/blockchain_logger.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from chainguard.blockchain import Blockchain
2
+
3
+ class BlockchainLogger:
4
+ def __init__(self):
5
+ self.blockchain = Blockchain()
6
+
7
+ def log_data(self, data: str):
8
+ """
9
+ Logs the provided data into the blockchain.
10
+ Args:
11
+ data (str): The data to be logged in the blockchain.
12
+ Returns:
13
+ dict: The details of the newly added block.
14
+ """
15
+ new_block = self.blockchain.add_block(data)
16
+ return {
17
+ "block_hash": new_block.hash,
18
+ "block_index": new_block.index,
19
+ "blockchain_length": len(self.blockchain.chain),
20
+ "previous_hash": new_block.previous_hash,
21
+ "timestamp": new_block.timestamp
22
+ }
23
+
24
+ def is_blockchain_valid(self):
25
+ """
26
+ Validates the integrity of the blockchain.
27
+ Returns:
28
+ bool: True if the blockchain is valid, False otherwise.
29
+ """
30
+ return self.blockchain.is_chain_valid()
chainguard/data_transfer.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import socket
2
+ from chainguard.encryption import AESCipher
3
+ from chainguard.blockchain_logger import BlockchainLogger
4
+
5
+ class SecureDataTransfer:
6
+ def __init__(self, password: str, host: str = 'localhost', port: int = 12345):
7
+ self.cipher = AESCipher(password)
8
+ self.host = host
9
+ self.port = port
10
+ self.blockchain_logger = BlockchainLogger()
11
+
12
+ def send_data(self, data: str):
13
+ """
14
+ Encrypts and sends data over the network, then logs it in the blockchain.
15
+ """
16
+ encrypted_data = self.cipher.encrypt(data)
17
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
18
+ s.connect((self.host, self.port))
19
+ s.sendall(encrypted_data.encode())
20
+ print(f"Sent encrypted data: {encrypted_data}")
21
+ # Log the transaction in the blockchain
22
+ self.blockchain_logger.log_data(encrypted_data)
23
+
24
+ def receive_data(self):
25
+ """
26
+ Receives encrypted data, decrypts it, and logs it in the blockchain.
27
+ """
28
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
29
+ s.bind((self.host, self.port))
30
+ s.listen()
31
+ conn, addr = s.accept()
32
+ with conn:
33
+ print(f"Connected by {addr}")
34
+ encrypted_data = conn.recv(1024).decode()
35
+ decrypted_data = self.cipher.decrypt(encrypted_data)
36
+ print(f"Received encrypted data: {encrypted_data}")
37
+ print(f"Decrypted data: {decrypted_data}")
38
+ # Log the transaction in the blockchain
39
+ self.blockchain_logger.log_data(encrypted_data)
40
+ return decrypted_data
41
+
42
+ def validate_blockchain(self):
43
+ """
44
+ Validates the blockchain's integrity.
45
+ """
46
+ return self.blockchain_logger.is_blockchain_valid()
chainguard/data_transformer.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from chainguard.blockchain_logger import BlockchainLogger
2
+
3
+ class DataTransformer:
4
+ def __init__(self):
5
+ """
6
+ Initializes a DataTransformer with a blockchain logger instance.
7
+ """
8
+ self.blockchain_logger = BlockchainLogger()
9
+
10
+ def secure_transform(self, data):
11
+ """
12
+ Securely transforms the input data by logging it into the blockchain.
13
+
14
+ Args:
15
+ data (dict): The log data or any data to be securely transformed.
16
+
17
+ Returns:
18
+ dict: A dictionary containing the original data, block hash, and blockchain length.
19
+ """
20
+ # Log the data into the blockchain
21
+ block_details = self.blockchain_logger.log_data(data)
22
+
23
+ # Return the block details and blockchain status
24
+ return {
25
+ "data": data,
26
+ **block_details
27
+ }
28
+
29
+ def validate_blockchain(self):
30
+ """
31
+ Validates the integrity of the blockchain.
32
+ Returns:
33
+ bool: True if the blockchain is valid, False otherwise.
34
+ """
35
+ return self.blockchain_logger.is_blockchain_valid()
chainguard/encryption.py ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
2
+ from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
3
+ from cryptography.hazmat.primitives import hashes
4
+ from cryptography.hazmat.backends import default_backend
5
+ from cryptography.hazmat.primitives import padding
6
+ from base64 import b64encode, b64decode
7
+ import os
8
+
9
+ class AESCipher:
10
+ def __init__(self, key: str):
11
+ self.backend = default_backend()
12
+ salt = os.urandom(16)
13
+ kdf = PBKDF2HMAC(
14
+ algorithm=hashes.SHA256(),
15
+ length=32,
16
+ salt=salt,
17
+ iterations=100000,
18
+ backend=self.backend
19
+ )
20
+ self.key = kdf.derive(key.encode())
21
+ self.iv = os.urandom(16)
22
+
23
+ def encrypt(self, plaintext: str) -> str:
24
+ padder = padding.PKCS7(algorithms.AES.block_size).padder()
25
+ padded_data = padder.update(plaintext.encode()) + padder.finalize()
26
+
27
+ cipher = Cipher(algorithms.AES(self.key), modes.CBC(self.iv), backend=self.backend)
28
+ encryptor = cipher.encryptor()
29
+ encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
30
+
31
+ return b64encode(self.iv + encrypted_data).decode('utf-8')
32
+
33
+ def decrypt(self, ciphertext: str) -> str:
34
+ encrypted_data = b64decode(ciphertext)
35
+ iv = encrypted_data[:16]
36
+ encrypted_data = encrypted_data[16:]
37
+
38
+ cipher = Cipher(algorithms.AES(self.key), modes.CBC(iv), backend=self.backend)
39
+ decryptor = cipher.decryptor()
40
+ padded_plaintext = decryptor.update(encrypted_data) + decryptor.finalize()
41
+
42
+ unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder()
43
+ plaintext = unpadder.update(padded_plaintext) + unpadder.finalize()
44
+
45
+ return plaintext.decode('utf-8')
chainguard/tests/__init__.py ADDED
File without changes
chainguard/tests/test_blockchain.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+ from chainguard.blockchain import Blockchain
3
+
4
+ class TestBlockchain(unittest.TestCase):
5
+ def setUp(self):
6
+ self.blockchain = Blockchain()
7
+
8
+ def test_genesis_block(self):
9
+ genesis_block = self.blockchain.chain[0]
10
+ self.assertEqual(genesis_block.data, "Genesis Block")
11
+
12
+ def test_add_block(self):
13
+ self.blockchain.add_block("Test Block")
14
+ latest_block = self.blockchain.get_latest_block()
15
+ self.assertEqual(latest_block.data, "Test Block")
16
+
17
+ def test_chain_validity(self):
18
+ self.blockchain.add_block("First block")
19
+ self.blockchain.add_block("Second block")
20
+ self.assertTrue(self.blockchain.is_chain_valid())
21
+
22
+ def test_chain_invalidity(self):
23
+ self.blockchain.add_block("First block")
24
+ self.blockchain.chain[1].data = "Tampered Data"
25
+ self.assertFalse(self.blockchain.is_chain_valid())
26
+
27
+ if __name__ == '__main__':
28
+ unittest.main()
29
+
chainguard/tests/test_data_transfer.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # chainguard/tests/test_data_transfer.py
2
+
3
+ import unittest
4
+ import threading
5
+ from chainguard.data_transfer import SecureDataTransfer
6
+
7
+ class TestSecureDataTransfer(unittest.TestCase):
8
+ def setUp(self):
9
+ self.password = "transferpassword123"
10
+ self.data = "Sensitive data being transferred."
11
+ self.server = SecureDataTransfer(self.password)
12
+ self.client = SecureDataTransfer(self.password)
13
+
14
+ def test_data_transfer(self):
15
+ def run_server():
16
+ received_data = self.server.receive_data()
17
+ self.assertEqual(received_data, self.data)
18
+
19
+ server_thread = threading.Thread(target=run_server)
20
+ server_thread.start()
21
+
22
+ self.client.send_data(self.data)
23
+ server_thread.join()
24
+
25
+ # Validate blockchain integrity after transfer
26
+ self.assertTrue(self.server.validate_blockchain())
27
+ self.assertTrue(self.client.validate_blockchain())
28
+
29
+ if __name__ == '__main__':
30
+ unittest.main()
chainguard/tests/test_encryption.py ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+ from chainguard.encryption import AESCipher
3
+
4
+
5
+ class TestAESCipher(unittest.TestCase):
6
+ def setUp(self):
7
+ self.password = "securepassword123"
8
+ self.cipher = AESCipher(self.password)
9
+
10
+ def test_encryption_decryption(self):
11
+ plaintext = "This is a secret message."
12
+ encrypted = self.cipher.encrypt(plaintext)
13
+ decrypted = self.cipher.decrypt(encrypted)
14
+
15
+ self.assertEqual(plaintext, decrypted)
16
+
17
+ def test_different_plaintext(self):
18
+ plaintext1 = "Message One"
19
+ plaintext2 = "Message Two"
20
+ encrypted1 = self.cipher.encrypt(plaintext1)
21
+ encrypted2 = self.cipher.encrypt(plaintext2)
22
+
23
+ self.assertNotEqual(encrypted1, encrypted2)
24
+ self.assertEqual(self.cipher.decrypt(encrypted1), plaintext1)
25
+ self.assertEqual(self.cipher.decrypt(encrypted2), plaintext2)
26
+
27
+
28
+ if __name__ == '__main__':
29
+ unittest.main()
visualisation/__init__.py ADDED
File without changes
visualisation/chainguard_graph_db.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from neo4j import GraphDatabase
2
+
3
+ class ChainGuardGraphDB:
4
+ def __init__(self, uri, user, password):
5
+ self.driver = GraphDatabase.driver(uri, auth=(user, password))
6
+
7
+ def close(self):
8
+ """Close the database connection."""
9
+ self.driver.close()
10
+
11
+ def create_node(self, label, properties):
12
+ """Create a node with the specified label and properties."""
13
+ with self.driver.session() as session:
14
+ session.write_transaction(self._create_and_return_node, label, properties)
15
+
16
+ @staticmethod
17
+ def _create_and_return_node(tx, label, properties):
18
+ query = (
19
+ f"CREATE (n:{label} {{"
20
+ + ", ".join([f"{k}: ${k}" for k in properties.keys()])
21
+ + "}}) RETURN n"
22
+ )
23
+ result = tx.run(query, **properties)
24
+ return result.single()[0]
25
+
26
+ def create_relationship(self, node1_label, node1_property, node2_label, node2_property, relationship_type):
27
+ """Create a relationship between two nodes."""
28
+ with self.driver.session() as session:
29
+ session.write_transaction(
30
+ self._create_and_return_relationship,
31
+ node1_label, node1_property, node2_label, node2_property, relationship_type
32
+ )
33
+
34
+ @staticmethod
35
+ def _create_and_return_relationship(tx, node1_label, node1_property, node2_label, node2_property, relationship_type):
36
+ query = (
37
+ f"MATCH (a:{node1_label} {{name: $node1_property}}), (b:{node2_label} {{name: $node2_property}}) "
38
+ f"CREATE (a)-[r:{relationship_type}]->(b) "
39
+ "RETURN r"
40
+ )
41
+ result = tx.run(query, node1_property=node1_property, node2_property=node2_property)
42
+ return result.single()[0]
43
+
44
+ def find_related_anomalies(self, transaction_name):
45
+ """Find all anomalies related to a specific blockchain transaction."""
46
+ with self.driver.session() as session:
47
+ result = session.run(
48
+ "MATCH (t:BlockchainTransaction {name: $transaction_name})-[:DETECTED_IN]->(a:Anomaly) "
49
+ "RETURN a.name, a.type, a.severity",
50
+ transaction_name=transaction_name
51
+ )
52
+ return [record for record in result]
53
+
54
+ def find_blockchain_transactions(self, anomaly_name):
55
+ """Find all blockchain transactions related to a specific anomaly."""
56
+ with self.driver.session() as session:
57
+ result = session.run(
58
+ "MATCH (a:Anomaly {name: $anomaly_name})<-[:DETECTED_IN]-(t:BlockchainTransaction) "
59
+ "RETURN t.name, t.amount, t.timestamp",
60
+ anomaly_name=anomaly_name
61
+ )
62
+ return [record for record in result]
63
+
64
+ def validate_blockchain(self):
65
+ """Validate the blockchain (this is a simplified example)."""
66
+ with self.driver.session() as session:
67
+ result = session.run(
68
+ "MATCH (b:BlockchainTransaction) "
69
+ "RETURN COUNT(b) as transaction_count"
70
+ )
71
+ count = result.single()["transaction_count"]
72
+ # Simplified validation: checks if there are transactions in the blockchain
73
+ return count > 0
74
+
75
+ # Example usage
76
+ if __name__ == "__main__":
77
+ # Connect to the database
78
+ db = ChainGuardGraphDB(uri="bolt://localhost:7687", user="neo4j", password="your_password")
79
+
80
+ # Create nodes
81
+ db.create_node("BlockchainTransaction", {"name": "Tx1", "amount": 100, "timestamp": "2024-09-01"})
82
+ db.create_node("Anomaly", {"name": "Anomaly1", "type": "Network", "severity": "High"})
83
+
84
+ # Create relationships
85
+ db.create_relationship("BlockchainTransaction", "Tx1", "Anomaly", "Anomaly1", "DETECTED_IN")
86
+
87
+ # Query related anomalies for a transaction
88
+ related_anomalies = db.find_related_anomalies("Tx1")
89
+ for anomaly in related_anomalies:
90
+ print(f"Related Anomaly: {anomaly['a.name']}, Type: {anomaly['a.type']}, Severity: {anomaly['a.severity']}")
91
+
92
+ # Query related transactions for an anomaly
93
+ related_transactions = db.find_blockchain_transactions("Anomaly1")
94
+ for tx in related_transactions:
95
+ print(f"Related Transaction: {tx['t.name']}, Amount: {tx['t.amount']}, Timestamp: {tx['t.timestamp']}")
96
+
97
+ # Validate the blockchain
98
+ is_valid = db.validate_blockchain()
99
+ print(f"Blockchain valid: {is_valid}")
100
+
101
+ # Close the connection
102
+ db.close()