From b0986fb5ab07e4eece7338a666c0b05d593beace Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Wed, 18 Jun 2025 21:11:46 +0700 Subject: [PATCH 1/7] Format --- terraform/environments/dev/variables.tf | 2 +- terraform/environments/prod/variables.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terraform/environments/dev/variables.tf b/terraform/environments/dev/variables.tf index 5601391..6148cf9 100644 --- a/terraform/environments/dev/variables.tf +++ b/terraform/environments/dev/variables.tf @@ -49,7 +49,7 @@ variable "public_subnets" { variable "app_version" { description = "Version of the application" type = string - default = "158b2cd63572d3115e89204ad3786762eac77996" + default = "158b2cd63572d3115e89204ad3786762eac77996" } variable "cognito_user_pool_id" { diff --git a/terraform/environments/prod/variables.tf b/terraform/environments/prod/variables.tf index c9fcb5f..6586298 100644 --- a/terraform/environments/prod/variables.tf +++ b/terraform/environments/prod/variables.tf @@ -49,7 +49,7 @@ variable "public_subnets" { variable "app_version" { description = "Version of the application" type = string - default = "158b2cd63572d3115e89204ad3786762eac77996" + default = "158b2cd63572d3115e89204ad3786762eac77996" } variable "cognito_user_pool_id" { From 90cab7361dd5925319df4449434389bd0e318237 Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Wed, 18 Jun 2025 21:15:28 +0700 Subject: [PATCH 2/7] Create resources --- terraform/environments/prod/main.tf | 2 ++ 1 file changed, 2 insertions(+) diff --git a/terraform/environments/prod/main.tf b/terraform/environments/prod/main.tf index bbb4dc6..c5f4ad4 100644 --- a/terraform/environments/prod/main.tf +++ b/terraform/environments/prod/main.tf @@ -8,6 +8,8 @@ terraform { } } +#run + provider "aws" { region = var.aws_region } From 42c8c54f3c46f6b2788889b8af5a52b19bc77d03 Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Wed, 18 Jun 2025 22:29:11 +0700 Subject: [PATCH 3/7] Create resource --- terraform/environments/dev/outputs.tf | 6 +----- terraform/environments/prod/outputs.tf | 6 +----- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/terraform/environments/dev/outputs.tf b/terraform/environments/dev/outputs.tf index efe8c93..abcba31 100644 --- a/terraform/environments/dev/outputs.tf +++ b/terraform/environments/dev/outputs.tf @@ -5,11 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = { - product_service = module.product_service.function_arn - trace_service = module.trace_service.function_arn - user_service = module.user_service.function_arn - } + value = module.lambda_service.function_arn } output "api_gateway_endpoint" { diff --git a/terraform/environments/prod/outputs.tf b/terraform/environments/prod/outputs.tf index efe8c93..abcba31 100644 --- a/terraform/environments/prod/outputs.tf +++ b/terraform/environments/prod/outputs.tf @@ -5,11 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = { - product_service = module.product_service.function_arn - trace_service = module.trace_service.function_arn - user_service = module.user_service.function_arn - } + value = module.lambda_service.function_arn } output "api_gateway_endpoint" { From c37ce2a2175e805537ccb1064c986a200774bdb0 Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Wed, 18 Jun 2025 22:31:50 +0700 Subject: [PATCH 4/7] Create resources --- terraform/environments/dev/outputs.tf | 2 +- terraform/environments/prod/outputs.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terraform/environments/dev/outputs.tf b/terraform/environments/dev/outputs.tf index abcba31..fff616c 100644 --- a/terraform/environments/dev/outputs.tf +++ b/terraform/environments/dev/outputs.tf @@ -5,7 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = module.lambda_service.function_arn + value = module.lambda_service.function_arn } output "api_gateway_endpoint" { diff --git a/terraform/environments/prod/outputs.tf b/terraform/environments/prod/outputs.tf index abcba31..fff616c 100644 --- a/terraform/environments/prod/outputs.tf +++ b/terraform/environments/prod/outputs.tf @@ -5,7 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = module.lambda_service.function_arn + value = module.lambda_service.function_arn } output "api_gateway_endpoint" { From f5e40d62a707f1b243a880b7a775f5ca2cd2246d Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Wed, 18 Jun 2025 22:39:47 +0700 Subject: [PATCH 5/7] Create resources --- terraform/environments/dev/outputs.tf | 2 +- terraform/environments/prod/outputs.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/terraform/environments/dev/outputs.tf b/terraform/environments/dev/outputs.tf index fff616c..204a1ae 100644 --- a/terraform/environments/dev/outputs.tf +++ b/terraform/environments/dev/outputs.tf @@ -5,7 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = module.lambda_service.function_arn + value = module.lambda_service.lambda_function_arn } output "api_gateway_endpoint" { diff --git a/terraform/environments/prod/outputs.tf b/terraform/environments/prod/outputs.tf index fff616c..204a1ae 100644 --- a/terraform/environments/prod/outputs.tf +++ b/terraform/environments/prod/outputs.tf @@ -5,7 +5,7 @@ output "dynamodb_table_name" { output "lambda_functions" { description = "ARNs of the Lambda functions" - value = module.lambda_service.function_arn + value = module.lambda_service.lambda_function_arn } output "api_gateway_endpoint" { From 5138fcd21b56c5f1e14d1e4470e4f256a299eea4 Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Thu, 19 Jun 2025 00:18:34 +0700 Subject: [PATCH 6/7] Create resources --- terraform/common/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/common/main.tf b/terraform/common/main.tf index 5b612b1..ec6d043 100644 --- a/terraform/common/main.tf +++ b/terraform/common/main.tf @@ -12,7 +12,7 @@ provider "aws" { region = var.aws_region } -# Tạo VPC.. +# Tạo VPC... module "vpc" { source = "../modules/vpc" From 732f729a47aecf31f6f99ffea0c82e06373496e0 Mon Sep 17 00:00:00 2001 From: Gia Bao Date: Thu, 19 Jun 2025 12:01:30 +0700 Subject: [PATCH 7/7] Upload blockchain --- blockchain/.env.example | 4 + blockchain/.gitignore | 32 ++++ blockchain/contracts/ProductRegistry.sol | 179 +++++++++++++++++++++++ blockchain/hardhat.config.js | 24 +++ blockchain/scripts/deploy.js | 16 ++ 5 files changed, 255 insertions(+) create mode 100644 blockchain/.env.example create mode 100644 blockchain/.gitignore create mode 100644 blockchain/contracts/ProductRegistry.sol create mode 100644 blockchain/hardhat.config.js create mode 100644 blockchain/scripts/deploy.js diff --git a/blockchain/.env.example b/blockchain/.env.example new file mode 100644 index 0000000..7870060 --- /dev/null +++ b/blockchain/.env.example @@ -0,0 +1,4 @@ +# .env.example +PRIVATE_KEY=your_64_char_hex_without_0x +INFURA_API_KEY=your_infura_project_id +CONTRACT_ADDRESS=deployed_contract_address_here diff --git a/blockchain/.gitignore b/blockchain/.gitignore new file mode 100644 index 0000000..9768eb2 --- /dev/null +++ b/blockchain/.gitignore @@ -0,0 +1,32 @@ +# Node.js / Next.js +node_modules/ +.next/ +npm-debug.log +package-lock.json +# Python +__pycache__/ +*.pyc +.venv/ + + +# Hardhat +artifacts/ +cache/ +typechain/ + +# Docker +*.env +docker-compose.override.yml + +# VS Code +.vscode/ + +# OS files +.DS_Store +Thumbs.db + +# Project-specific +.env +*.txt +DevSecOps_Blockchain_App.code-workspace + diff --git a/blockchain/contracts/ProductRegistry.sol b/blockchain/contracts/ProductRegistry.sol new file mode 100644 index 0000000..68cb247 --- /dev/null +++ b/blockchain/contracts/ProductRegistry.sol @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract ProductRegistry { + struct Product { + string name; + string batch; + string manufacturer; + string status; + uint256 timestamp; + bool exists; + } + + struct TraceRecord { + string stage; + string company; + string location; + uint256 timestamp; + bool exists; + } + + mapping(string => Product) public products; + mapping(string => TraceRecord[]) public productTraces; + mapping(string => uint256) public traceCount; + + event ProductRegistered(string productId, string name, string manufacturer); + event ProductStatusUpdated(string productId, string newStatus); + event TraceRecordAdded(string productId, string stage, string company, string location); + + modifier productExists(string memory productId) { + require(products[productId].exists, "Product does not exist"); + _; + } + + function registerProduct( + string memory productId, + string memory name, + string memory batch, + string memory manufacturer + ) public { + require(!products[productId].exists, "Product already exists"); + require(bytes(productId).length > 0, "Product ID cannot be empty"); + require(bytes(name).length > 0, "Product name cannot be empty"); + require(bytes(manufacturer).length > 0, "Manufacturer cannot be empty"); + + products[productId] = Product({ + name: name, + batch: batch, + manufacturer: manufacturer, + status: "Created", + timestamp: block.timestamp, + exists: true + }); + + emit ProductRegistered(productId, name, manufacturer); + } + + function updateProductStatus(string memory productId, string memory newStatus) + public + productExists(productId) + { + require(bytes(newStatus).length > 0, "Status cannot be empty"); + + products[productId].status = newStatus; + emit ProductStatusUpdated(productId, newStatus); + } + + function addTraceRecord( + string memory productId, + string memory stage, + string memory company, + string memory location + ) public productExists(productId) { + require(bytes(stage).length > 0, "Stage cannot be empty"); + require(bytes(company).length > 0, "Company cannot be empty"); + require(bytes(location).length > 0, "Location cannot be empty"); + + TraceRecord memory newTrace = TraceRecord({ + stage: stage, + company: company, + location: location, + timestamp: block.timestamp, + exists: true + }); + + productTraces[productId].push(newTrace); + traceCount[productId] = productTraces[productId].length; + + emit TraceRecordAdded(productId, stage, company, location); + } + + function getProduct(string memory productId) + public + view + returns ( + string memory, + string memory, + string memory, + string memory, + uint256 + ) + { + require(products[productId].exists, "Product not found"); + Product memory p = products[productId]; + return (p.name, p.batch, p.manufacturer, p.status, p.timestamp); + } + + function getTraceRecord(string memory productId, uint256 index) + public + view + returns ( + string memory, + string memory, + string memory, + uint256 + ) + { + require(products[productId].exists, "Product not found"); + require(index < productTraces[productId].length, "Trace record index out of bounds"); + + TraceRecord memory trace = productTraces[productId][index]; + return (trace.stage, trace.company, trace.location, trace.timestamp); + } + + function getTraceCount(string memory productId) + public + view + returns (uint256) + { + require(products[productId].exists, "Product not found"); + return traceCount[productId]; + } + + function getAllTraces(string memory productId) + public + view + returns ( + string[] memory stages, + string[] memory companies, + string[] memory locations, + uint256[] memory timestamps + ) + { + require(products[productId].exists, "Product not found"); + + uint256 count = productTraces[productId].length; + stages = new string[](count); + companies = new string[](count); + locations = new string[](count); + timestamps = new uint256[](count); + + for (uint256 i = 0; i < count; i++) { + TraceRecord memory trace = productTraces[productId][i]; + stages[i] = trace.stage; + companies[i] = trace.company; + locations[i] = trace.location; + timestamps[i] = trace.timestamp; + } + + return (stages, companies, locations, timestamps); + } + + function productExistsCheck(string memory productId) + public + view + returns (bool) + { + return products[productId].exists; + } + + // Emergency function to verify contract integrity + function getContractInfo() + public + pure + returns (string memory, string memory) + { + return ("ProductRegistry", "2.0.0"); + } +} \ No newline at end of file diff --git a/blockchain/hardhat.config.js b/blockchain/hardhat.config.js new file mode 100644 index 0000000..711fd13 --- /dev/null +++ b/blockchain/hardhat.config.js @@ -0,0 +1,24 @@ +require("dotenv").config(); +console.log("PRIVATE_KEY:", process.env.PRIVATE_KEY); +console.log("INFURA_API_KEY:", process.env.INFURA_API_KEY); +console.log("CONTRACT_ADDRESS:", process.env.CONTRACT_ADDRESS); + +require("@nomiclabs/hardhat-ethers"); + +module.exports = { + solidity: "0.8.20", + defaultNetwork: "sepolia", + networks: { + hardhat: {}, + sepolia: { + url: `https://sepolia.infura.io/v3/${process.env.INFURA_API_KEY}`, + accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY.trim()] : [], + }, + }, + paths: { + sources: "./contracts", + tests: "./test", + cache: "./cache", + artifacts: "./artifacts", + }, +}; diff --git a/blockchain/scripts/deploy.js b/blockchain/scripts/deploy.js new file mode 100644 index 0000000..5b60309 --- /dev/null +++ b/blockchain/scripts/deploy.js @@ -0,0 +1,16 @@ +const hre = require("hardhat"); + +async function main() { + console.log("Deploying to Sepolia..."); + + const ProductRegistry = await hre.ethers.getContractFactory("ProductRegistry"); + const registry = await ProductRegistry.deploy(); + + await registry.deployed(); + console.log("✅ Contract deployed to:", registry.address); +} + +main().catch((error) => { + console.error(error); + process.exitCode = 1; +});