Skip to content

Commit 37c29dd

Browse files
Use transaction in data
1 parent 2a686a3 commit 37c29dd

File tree

16 files changed

+310
-25
lines changed

16 files changed

+310
-25
lines changed

.github/workflows/ci.yml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
name: Ruby CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
9+
jobs:
10+
rubocop:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 5
13+
env:
14+
RUBOCOP_CACHE_ROOT: tmp/rubocop
15+
steps:
16+
- name: Checkout repository
17+
uses: actions/checkout@v4
18+
19+
- name: Set up Ruby
20+
uses: ruby/setup-ruby@v1
21+
with:
22+
bundler-cache: true
23+
24+
- name: Setup RuboCop cache
25+
uses: actions/cache@v4
26+
id: cache-rubocop
27+
with:
28+
path: ${{ env.RUBOCOP_CACHE_ROOT }}
29+
key: ${{ runner.os }}-rubocop-${{ hashFiles('Gemfile.lock') }}
30+
restore-keys: |
31+
${{ runner.os }}-rubocop-
32+
33+
- name: Run RuboCop
34+
run: bundle exec rubocop --format github --format clang
35+
36+
tests:
37+
runs-on: ubuntu-latest
38+
timeout-minutes: 10
39+
env:
40+
COVER: true
41+
steps:
42+
- uses: actions/checkout@v4
43+
44+
- name: Set up Ruby
45+
uses: ruby/setup-ruby@v1
46+
with:
47+
bundler-cache: true
48+
49+
- name: Run tests
50+
run: bundle exec rspec
51+
52+
- name: Upload coverage artifact
53+
uses: actions/upload-artifact@v4
54+
with:
55+
name: coverage
56+
path: coverage
57+
58+
- name: Coveralls
59+
uses: coverallsapp/github-action@v2
60+
with:
61+
github-token: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Ruby
2+
*.gem
3+
*.rbc
4+
/.config
5+
/coverage/
6+
/InstalledFiles
7+
/pkg/
8+
/spec/reports/
9+
/spec/examples.txt
10+
/test/tmp/
11+
/test/version_tmp/
12+
/tmp/
13+
14+
# Used by dotenv library
15+
.env
16+
17+
# RuboCop cache
18+
.rubocop_cache/
19+
20+
# Bundler
21+
!bin/mcp_server.rb
22+
!bin/http_server.rb
23+
.bundle
24+
25+
# Documentation
26+
doc/
27+
.yardoc/
28+
29+
# IntelliJ IDEA
30+
/.idea/
31+
32+
# VS Code
33+
/.vscode/
34+
35+
# Generated by Mac
36+
.DS_Store
37+
38+
# Log files
39+
*.log
40+
41+
# Rails
42+
/public/system/
43+
/public/assets/
44+
/public/packs/
45+
/public/packs-test/
46+
/node_modules/
47+
/yarn-error.log
48+
/yarn.lock
49+
50+
# RSpec
51+
.tmp/rspec_examples.txt
52+
rspec_examples.txt

Gemfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,6 @@ group :development, :test do
1414
gem "pry"
1515
gem "rspec"
1616
gem "rubocop", require: false
17+
gem "simplecov", require: false
18+
gem "simplecov-lcov", require: false
1719
end

Gemfile.lock

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ GEM
1414
coderay (1.1.3)
1515
concurrent-ruby (1.3.5)
1616
diff-lcs (1.6.2)
17+
docile (1.4.1)
1718
dry-configurable (1.2.0)
1819
dry-core (~> 1.0, < 2)
1920
zeitwerk (~> 2.6)
@@ -85,6 +86,13 @@ GEM
8586
parser (>= 3.3.7.2)
8687
prism (~> 1.4)
8788
ruby-progressbar (1.13.0)
89+
simplecov (0.22.0)
90+
docile (~> 1.1)
91+
simplecov-html (~> 0.11)
92+
simplecov_json_formatter (~> 0.1)
93+
simplecov-html (0.13.2)
94+
simplecov-lcov (0.9.0)
95+
simplecov_json_formatter (0.1.4)
8896
unicode-display_width (3.2.0)
8997
unicode-emoji (~> 4.1)
9098
unicode-emoji (4.1.0)
@@ -102,6 +110,8 @@ DEPENDENCIES
102110
resol!
103111
rspec
104112
rubocop
113+
simplecov
114+
simplecov-lcov
105115
zeitwerk
106116

107117
RUBY VERSION

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2025 dude
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

app/case/block/create_genesis.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
class Case::Block::CreateGenesis < Case::Base
4+
param :difficulty, Types::Integer
5+
6+
def call
7+
genesis_input = Value::Transaction::Input.new(transaction_id: "0" * 64, output_index: 0)
8+
genesis_output = Value::Transaction::Output.new(address: "genesis_wallet", amount: BigDecimal("0"))
9+
genesis_transaction = Entity::Transaction.build([genesis_input], [genesis_output])
10+
11+
block = Entity::Block.new(
12+
index: 0,
13+
previous_hash: "0" * 64,
14+
timestamp: Time.now.utc.to_i,
15+
data: [genesis_transaction],
16+
).mine!(difficulty)
17+
18+
success!(block)
19+
end
20+
end

app/case/blockchain/add.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
class Case::Blockchain::Add < Case::Base
44
param :blockchain, Types.Instance(Entity::Blockchain)
5-
param :data, Types::Array
5+
param :data, Types::Array.of(Types.Instance(Entity::Transaction))
66

77
def call
88
self.block = create_block!

app/case/blockchain/create.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ class Case::Blockchain::Create < Case::Base
44
param :difficulty, Types::Integer, default: proc { SimpleBlockchain.default_difficulty }
55

66
def call
7-
genesis_block = Entity::Block.build_genesis(difficulty)
7+
genesis_block = Case::Block::CreateGenesis.call!(difficulty)
88
blockchain = Entity::Blockchain.new(blocks: [genesis_block], difficulty: difficulty)
99

1010
success!(blockchain)

app/case/blockchain/validate.rb

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,26 @@ def call
1111

1212
private
1313

14+
attr_accessor :previous_block, :block
15+
1416
def process_validation
1517
blockchain.blocks.each_cons(2).all? do |previous_block, block|
16-
block.previous_hash == previous_block.block_hash && block.block_hash.start_with?("0" * blockchain.difficulty)
18+
self.previous_block = previous_block
19+
self.block = block
20+
21+
valid_previous_hash? && valid_difficulty? && valid_current_hash?
1722
end
1823
end
24+
25+
def valid_previous_hash?
26+
block.previous_hash == previous_block.block_hash
27+
end
28+
29+
def valid_current_hash?
30+
block.calculate_hash == block.block_hash
31+
end
32+
33+
def valid_difficulty?
34+
block.block_hash.start_with?("0" * blockchain.difficulty)
35+
end
1936
end

app/entity/block.rb

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ class Entity::Block < Entity::Base
77
attribute :nonce, Types::Integer.default(0)
88
attribute :block_hash, Types::String.optional.default(nil)
99

10-
attribute :data, Types::Array
11-
12-
def self.build_genesis(difficulty)
13-
new(index: 0, previous_hash: "0" * 64, timestamp: Time.now.utc.to_i, data: ["Initial block"]).mine!(difficulty)
14-
end
10+
attribute :data, Types::Array.of(Types.Instance(Entity::Transaction))
1511

1612
def mine!(difficulty)
1713
self.block_hash = loop do
@@ -24,8 +20,6 @@ def mine!(difficulty)
2420
self
2521
end
2622

27-
private
28-
2923
def calculate_hash
3024
Digest::SHA256.hexdigest([index, previous_hash, timestamp, data.join, nonce].join("|"))
3125
end

0 commit comments

Comments
 (0)