├── .ruby-gemset ├── .ruby-version ├── exe └── cryptoruby ├── .DS_Store ├── .rspec ├── lib ├── cryptoruby │ ├── version.rb │ ├── block.rb │ └── blockchain.rb └── cryptoruby.rb ├── spec ├── .DS_Store ├── cryptoruby_spec.rb └── spec_helper.rb ├── .travis.yml ├── Rakefile ├── bin ├── setup └── console ├── Gemfile ├── .gitignore ├── LICENSE.txt ├── Gemfile.lock ├── cryptoruby.gemspec ├── CODE_OF_CONDUCT.md └── README.md /.ruby-gemset: -------------------------------------------------------------------------------- 1 | cryptoruby -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.4.1 -------------------------------------------------------------------------------- /exe/cryptoruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "cryptoruby" 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamdan85/cryptoruby/HEAD/.DS_Store -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --format documentation 2 | --color 3 | --require spec_helper 4 | -------------------------------------------------------------------------------- /lib/cryptoruby/version.rb: -------------------------------------------------------------------------------- 1 | module Cryptoruby 2 | VERSION = "0.1.3" 3 | end 4 | -------------------------------------------------------------------------------- /spec/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Hamdan85/cryptoruby/HEAD/spec/.DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | rvm: 4 | - 2.4.1 5 | before_install: gem install bundler -v 1.16.0 6 | -------------------------------------------------------------------------------- /lib/cryptoruby.rb: -------------------------------------------------------------------------------- 1 | require "cryptoruby/version" 2 | 3 | module Cryptoruby 4 | require 'cryptoruby/blockchain' 5 | end 6 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /spec/cryptoruby_spec.rb: -------------------------------------------------------------------------------- 1 | RSpec.describe Cryptoruby do 2 | it "has a version number" do 3 | expect(Cryptoruby::VERSION).not_to be nil 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } 4 | 5 | # Specify your gem's dependencies in cryptoruby.gemspec 6 | gemspec -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle/ 2 | /.yardoc 3 | /_yardoc/ 4 | /coverage/ 5 | /doc/ 6 | /pkg/ 7 | /spec/reports/ 8 | /tmp/ 9 | 10 | # rspec failure tracking 11 | .rspec_status 12 | /.idea/** 13 | /spec/coverage/** -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "bundler/setup" 4 | require "cryptoruby" 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require "pry" 11 | # Pry.start 12 | 13 | require "irb" 14 | IRB.start(__FILE__) 15 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require "bundler/setup" 2 | require "cryptoruby" 3 | require "rspec" 4 | require "simplecov" 5 | require "coveralls" 6 | 7 | SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter::new([ 8 | SimpleCov::Formatter::HTMLFormatter, 9 | Coveralls::SimpleCov::Formatter 10 | ]) 11 | SimpleCov.start 12 | 13 | RSpec.configure do |config| 14 | # Enable flags like --only-failures and --next-failure 15 | config.example_status_persistence_file_path = ".rspec_status" 16 | 17 | # Disable RSpec exposing methods globally on `Module` and `main` 18 | config.disable_monkey_patching! 19 | 20 | config.expect_with :rspec do |c| 21 | c.syntax = :expect 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Gabriel Hamdan 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 13 | all 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 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | cryptoruby (0.1.3) 5 | 6 | GEM 7 | remote: https://rubygems.org/ 8 | specs: 9 | awesome_print (0.4.0) 10 | coveralls (0.8.21) 11 | json (>= 1.8, < 3) 12 | simplecov (~> 0.14.1) 13 | term-ansicolor (~> 1.3) 14 | thor (~> 0.19.4) 15 | tins (~> 1.6) 16 | diff-lcs (1.3) 17 | docile (1.1.5) 18 | json (2.1.0) 19 | rake (10.5.0) 20 | rspec (3.7.0) 21 | rspec-core (~> 3.7.0) 22 | rspec-expectations (~> 3.7.0) 23 | rspec-mocks (~> 3.7.0) 24 | rspec-core (3.7.0) 25 | rspec-support (~> 3.7.0) 26 | rspec-expectations (3.7.0) 27 | diff-lcs (>= 1.2.0, < 2.0) 28 | rspec-support (~> 3.7.0) 29 | rspec-mocks (3.7.0) 30 | diff-lcs (>= 1.2.0, < 2.0) 31 | rspec-support (~> 3.7.0) 32 | rspec-support (3.7.0) 33 | simplecov (0.14.1) 34 | docile (~> 1.1.0) 35 | json (>= 1.8, < 3) 36 | simplecov-html (~> 0.10.0) 37 | simplecov-html (0.10.2) 38 | term-ansicolor (1.6.0) 39 | tins (~> 1.0) 40 | thor (0.19.4) 41 | tins (1.16.3) 42 | 43 | PLATFORMS 44 | ruby 45 | 46 | DEPENDENCIES 47 | awesome_print (~> 0) 48 | bundler (~> 1.16) 49 | coveralls (>= 0.7.0) 50 | cryptoruby! 51 | rake (~> 10.0) 52 | rspec (~> 3.0) 53 | simplecov (>= 0.8.2) 54 | 55 | BUNDLED WITH 56 | 1.16.0 57 | -------------------------------------------------------------------------------- /lib/cryptoruby/block.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | require 'openssl' 3 | 4 | module Cryptoruby 5 | class Blockchain 6 | class Block 7 | attr_reader :blockchain, :index, :previous_hash, :data, :timestamp, :hash, :difficult, :nonce 8 | def initialize(args) 9 | setup_args(args) 10 | @timestamp = Time.now.to_i 11 | @difficult = difficult 12 | @nonce = 0 13 | mine 14 | end 15 | 16 | def digest_hash 17 | OpenSSL::Digest::SHA512.hexdigest "#{index}#{previous_hash}#{stringfied_data}#{timestamp.to_s}#{nonce}" 18 | end 19 | 20 | private 21 | 22 | def mine 23 | loop do 24 | @nonce += 1 25 | @hash = digest_hash 26 | break if @hash[0..@difficult] =~ /^0*$/ || @difficult.zero? 27 | end 28 | end 29 | 30 | def stringfied_data 31 | case @data 32 | when String 33 | @data 34 | when Hash 35 | @data.to_json 36 | when Array 37 | @data.to_json 38 | else 39 | raise 'Invalid Data' 40 | end 41 | end 42 | 43 | def setup_args(args) 44 | @index = args[:index] || 0 45 | @previous_hash = args[:previous_hash] || nil 46 | @data = args[:data] || 'Genesis Block' 47 | @difficult = args[:difficult] || 0 48 | @blockchain = args[:blockchain] 49 | end 50 | end 51 | end 52 | end -------------------------------------------------------------------------------- /cryptoruby.gemspec: -------------------------------------------------------------------------------- 1 | 2 | lib = File.expand_path("../lib", __FILE__) 3 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) 4 | require "cryptoruby/version" 5 | 6 | Gem::Specification.new do |spec| 7 | spec.name = "cryptoruby" 8 | spec.version = Cryptoruby::VERSION 9 | spec.authors = ["Gabriel Hamdan"] 10 | spec.email = ["ghamdan.eng@gmail.com"] 11 | 12 | spec.summary = %q{Ruby's Blockchain} 13 | spec.description = %q{Ruby's Blockchain} 14 | spec.homepage = "https://github.com/hamdan85/cryptoruby" 15 | spec.license = "MIT" 16 | 17 | # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host' 18 | # to allow pushing to a single host or delete this section to allow pushing to any host. 19 | # if spec.respond_to?(:metadata) 20 | # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" 21 | # else 22 | # raise "RubyGems 2.0 or newer is required to protect against " \ 23 | # "public gem pushes." 24 | # end 25 | 26 | spec.files = `git ls-files -z`.split("\x0").reject do |f| 27 | f.match(%r{^(test|spec|features)/}) 28 | end 29 | spec.bindir = "exe" 30 | spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } 31 | spec.require_paths = ["lib"] 32 | 33 | spec.add_development_dependency "bundler", "~> 1.16" 34 | spec.add_development_dependency "rake", "~> 10.0" 35 | spec.add_development_dependency "rspec", "~> 3.0" 36 | spec.add_development_dependency "simplecov", ">= 0.8.2" 37 | spec.add_development_dependency "awesome_print", "~> 0" 38 | spec.add_development_dependency "coveralls", ">= 0.7.0" 39 | end 40 | -------------------------------------------------------------------------------- /lib/cryptoruby/blockchain.rb: -------------------------------------------------------------------------------- 1 | require 'cryptoruby/block' 2 | require 'json' 3 | 4 | module Cryptoruby 5 | class Blockchain 6 | attr_accessor :blocks, :difficult 7 | attr_reader :index 8 | 9 | def initialize(difficult = 0) 10 | @blocks = [] 11 | @index = 0 12 | @difficult = difficult 13 | generate_genesis_block 14 | end 15 | 16 | def add_block(data) 17 | @index += 1 18 | @blocks << Block.new(index: index, previous_hash: last_block.hash, data: data, difficult: @difficult, blockchain: self) 19 | end 20 | 21 | def <<(data) 22 | add_block(data) 23 | end 24 | 25 | def is_valid? 26 | blocks[1..-1].sort_by{|block| block.index }.each_with_index do |current_block, index| 27 | previous_block = blocks[index] 28 | 29 | if current_block.hash != current_block.digest_hash 30 | p "Hash is different from digest on block of index #{index + 1}" 31 | return false 32 | end 33 | 34 | if current_block.index != previous_block.index + 1 35 | p 'Index is not sequential' 36 | return false 37 | end 38 | if current_block.previous_hash != previous_block.hash 39 | p 'Previous hash doesnt match with the current one' 40 | return false 41 | end 42 | end 43 | return true 44 | end 45 | 46 | def export 47 | { 48 | difficult: difficult, 49 | blocks: blocks.map{ |block| 50 | { 51 | index: block.index, 52 | previous_hash: block.previous_hash, 53 | data: block.data, 54 | timestamp: block.timestamp, 55 | hash: block.hash, 56 | difficult: block.difficult, 57 | nonce: block.nonce 58 | } 59 | } 60 | } 61 | end 62 | 63 | def last_block 64 | @blocks.last 65 | end 66 | 67 | private 68 | 69 | def generate_genesis_block 70 | @blocks << Block.new(index: 0, blockchain: self, difficult: @difficult) 71 | end 72 | end 73 | end -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, gender identity and expression, level of experience, 9 | nationality, personal appearance, race, religion, or sexual identity and 10 | orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at ghamdan.eng@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at [http://contributor-covenant.org/version/1/4][version] 72 | 73 | [homepage]: http://contributor-covenant.org 74 | [version]: http://contributor-covenant.org/version/1/4/ 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Gem Version](https://badge.fury.io/rb/cryptoruby.svg)](https://badge.fury.io/rb/cryptoruby) 2 | [![Maintainability](https://api.codeclimate.com/v1/badges/bad219ce2847552d2d56/maintainability)](https://codeclimate.com/github/Hamdan85/cryptoruby/maintainability) 3 | [![Dependency Status](https://gemnasium.com/badges/github.com/Hamdan85/cryptoruby.svg)](https://gemnasium.com/github.com/Hamdan85/cryptoruby) 4 | [![Build Status](https://travis-ci.org/Hamdan85/cryptoruby.svg?branch=master)](https://travis-ci.org/Hamdan85/cryptoruby) 5 | 6 | # Cryptoruby 7 | 8 | How about to have your own blockchain? This gems allow your application to have it... 9 | 10 | ## Installation 11 | 12 | Add this line to your application's Gemfile: 13 | 14 | ```ruby 15 | gem 'cryptoruby' 16 | ``` 17 | 18 | And then execute: 19 | 20 | $ bundle 21 | 22 | Or install it yourself as: 23 | 24 | $ gem install cryptoruby 25 | 26 | ## Usage 27 | 28 | In order to use this gem you'll need to initialize your block first: 29 | ````ruby 30 | blockchain = Cryptoruby::Blockchain.new 31 | ```` 32 | 33 | This will create your blockchain and initiate with and empty first block. The Genesis one. 34 | 35 | After that, all youll need to do is to add some blocks to it: 36 | ````ruby 37 | data = {amount: 3000} 38 | blockchain.add_block(data) # or 39 | blockchain << data 40 | ```` 41 | 42 | You see... data can be anything. You can store strings, jsons, arrays, even base64 files. 43 | 44 | Then, after adding blocks, you'll need to check if your chain is still valid right? 45 | ````ruby 46 | blockchain.is_valid? # returns true or false 47 | ```` 48 | Try changing something in the blocks and validating again... this works man... for real! 49 | 50 | Ah... almost forgot... you can set yours blockchain's difficult too... 51 | To do so, all you need to do is to change (or instantiate from the beginning) the difficult parameter 52 | ````ruby 53 | blockchain = Cryptoruby::Blockchain.new(3) 54 | ```` 55 | The difficult is default to 0, but you can set it for whatever you want. In this example, it was set to 3 zeroes in the start of the hash. 56 | 57 | And, in the end, you'll be able to export everything. How About That? 58 | ```ruby 59 | blockchain.export 60 | ``` 61 | 62 | ## Full Usage 63 | 64 | ````ruby 65 | blockchain = Cryptoruby::Blockchain.new(2) # Difficult of 2 initial zeros 66 | #, @timestamp=1513486966, @nonce=6995, @hash="000449121a75ece0e52adbc12cf60bde1f9fe3f7c627f1163c412d58cfc2a41fddcf275814fc8acdbf685b993b07fc3f8bb0d2664294af418a47198c5b7eb90f">], @index=0, @difficult=2> 67 | blockchain << { name: 'last night', amount_in_cents: 35000 } 68 | [#, @timestamp=1513486966, @nonce=6995, @hash="000449121a75ece0e52adbc12cf60bde1f9fe3f7c627f1163c412d58cfc2a41fddcf275814fc8acdbf685b993b07fc3f8bb0d2664294af418a47198c5b7eb90f">, #"last night", :amount_in_cents=>35000}, @difficult=2, @blockchain=#, @timestamp=1513486969, @nonce=4565, @hash="0008767c32faa0bdf72229f1b3d5e55fe590ea7b9dc6791804a831ac4229e074ddc58b1ee9369d7af16d0e89f4f3627df626483a248b720337620f4c26d9e2e7">] 69 | blockchain.export 70 | { 71 | :difficult => 2, 72 | :blocks => [ 73 | [0] { 74 | :index => 0, 75 | :previous_hash => nil, 76 | :data => "Genesis Block", 77 | :timestamp => 1513486966, 78 | :hash => "000449121a75ece0e52adbc12cf60bde1f9fe3f7c627f1163c412d58cfc2a41fddcf275814fc8acdbf685b993b07fc3f8bb0d2664294af418a47198c5b7eb90f", 79 | :difficult => 2, 80 | :nonce => 6995 81 | }, 82 | [1] { 83 | :index => 1, 84 | :previous_hash => "000449121a75ece0e52adbc12cf60bde1f9fe3f7c627f1163c412d58cfc2a41fddcf275814fc8acdbf685b993b07fc3f8bb0d2664294af418a47198c5b7eb90f", 85 | :data => { 86 | :name => "last night", 87 | :amount_in_cents => 35000 88 | }, 89 | :timestamp => 1513486969, 90 | :hash => "0008767c32faa0bdf72229f1b3d5e55fe590ea7b9dc6791804a831ac4229e074ddc58b1ee9369d7af16d0e89f4f3627df626483a248b720337620f4c26d9e2e7", 91 | :difficult => 2, 92 | :nonce => 4565 93 | } 94 | ] 95 | } 96 | ```` 97 | 98 | Hope you like it!! 99 | 100 | ## Development 101 | 102 | It'll be awesome if you help me to get it better. After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 103 | 104 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 105 | 106 | ## Contributing 107 | 108 | Bug reports and pull requests are welcome on GitHub at https://github.com/hamdan85/cryptoruby. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct. 109 | 110 | ## License 111 | 112 | The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). 113 | 114 | ## Code of Conduct 115 | 116 | Everyone interacting in the Cryptoruby project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/hamdan85/cryptoruby/blob/master/CODE_OF_CONDUCT.md). 117 | --------------------------------------------------------------------------------