GithubHelp home page GithubHelp logo

vkoskiv / vaporcoin Goto Github PK

View Code? Open in Web Editor NEW
69.0 8.0 3.0 150 KB

A peer-to-peer blockchain ledger, built with Swift, using Vapor

License: MIT License

Swift 100.00%
vapor-swift blockchain-ledger peer-to-peer swift swift-language bitcoin

vaporcoin's Introduction

VaporCoin

MIT License Build Status Swift 4.1

Synopsis

VaporCoin is a simple blockchain transaction ledger implementation, built in Swift using Vapor.

Goals

Functional, simple and easy to understand implementation that favors learning over robust security and usability. This is not intended to be an 'altcoin'

Specifications

Blocks:

  • Block time 60 seconds
  • 6000 transactions per block (Effective 100 txns/s rate)
  • Block difficulty updated every 60 blocks (hourly)
  • Block reward 50 full units/block (1 unit = 100 000 000 sub-units)
  • Block reward halved every 4 years (2 102 400 blocks at 525 600 blocks per year)
  • Total amount of full units will be roughly ~209 829 375

Transactions:

  • Simplified Bitcoin-style transactions, UTXO (No scripting capability)
  • ECDSA signatures

Proof of Work (PoW) algorithm:

  • Simplified Bitcoin-style. Single SHA256 hash of block header

Block header:

  • Previous hash
  • Merkle root of transactions in block
  • UNIX timestamp
  • Target difficulty
  • Nonce (32 bit)

TODO

  • JSON WebSocket p2p communication / Incomplete
  • Peer discovery
  • Locally hosted web interface to send and receive transactions, change settings and monitor blockchain status.
  • Fractional difficulty adjustment (Using BigInt)
  • Database logic
  • Proper node syncing
  • UTXO Transactions
  • Establish consensus

Getting started

brew install vapor/tap/vapor

In project root directory:
vapor update
vapor build 
vapor run

If you are using Xcode, make sure to select `My Mac` as target, and select the `Run` scheme.

Difficulty Factor

To mine a block, you can lower the diffBits amount in Droplet+Setup.swift line 17:

let miner = Miner(coinbase: "coinbaseAddressNotImplementedYet", diffBits: 20, threadCount: 4)

Tips

Get me some coffee:

ETH: 0x1e8e9c1a1b71ff88829b962cfa7190d074343b37
LTC: LZc2QcyZGuhHF18s96VAUPpByZq2S8yCsj
ZEC: t1UukAm25iRLTyTQfhX6WfRBzMjp8UCmy4a

vaporcoin's People

Contributors

johndpope avatar vkoskiv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

vaporcoin's Issues

Implement automatic, and more secure keypair generation, loading and storing.

Right now the keypair is manually generated with
openssl ecparam -genkey -name secp256k1 -noout -out private.pem
openssl ec -in private.pem -pubout -out public.pem

And the path to these is provided in State.swift:71
self.clientWallet = Wallet(withKeyPath: "/path/to/your/keys/")

Preferrably we'd generate these if need be, and store them in a better place. This works for now, however, since this implementation is purely meant to be used by interested developers, not end-users.

dockerfile + mining

Need to get my head around this -
with one line - it's possible to bring up a node in docker which will start mining.

docker run -it --rm -v "/tmp:/tendermint" tendermint/tendermint node --proxy_app=dummy2

screen shot 2018-01-15 at 11 04 47 pm

I'm thinking that we should follow suit so we include a swift linux docker file that can be brought online - this would then start syncing blockchain.
https://github.com/tendermint/tendermint/blob/master/DOCKER/Dockerfile

I have a swift server side docker file layering around this will help test blockchain syncing.

Build a blockchain management system (Database integration with Fluent)

We should never directly interact with the state.blockChain array.
Instead, we need to build a set of functions to interact with the blockchain.
These functions keep N most recent blocks in-memory, and store older blocks into the database.
When requesting a block, these functions determine the status of that block and pull it from the db if needed.

clarification - on vapor / droplet threading DispatchQueue vs. OperationQueue

in an attempt to bring some clarity to what's going on - started digging into the threading and surprised by this.

When we spawn the DispatchQueue.concurrentPerform this is not originating from the main thread to my surprise.

screen shot 2018-01-11 at 12 09 34 pm

I must admit, I am much more comfortable using operation queues which are built on top of GCD.
This simplified code - would fire up multiple operations to mine the block hash.
Once we find the hash - all queued operations are stopped.

this queue can be governed from other classes
screen shot 2018-01-11 at 12 12 57 pm

I'm thinking the mining should be able to get access to a main thread - that would help centralize state.

But doesn't seem like this code can run

DispatchQueue.main.async {
print("hello")
// or do something more useful
}

vapor/vapor#1268

basically looking to do this

extension Droplet {
    public func setup() throws {
        try setupRoutes()
        
        //For now init state by reading value from there.
        print("BlockChain count: \(state.blockChain.count)")
        
        DispatchQueue.main.async { // this code won't run
            self.mine()
        }

    }
    
    func mine(){
       
            let miner = Miner(coinbase: "asdf", diff: 5000, threadCount: 4)
            let newBlock = Block(prevHash: state.getPreviousBlock().blockHash, depth: state.blockDepth, txns: [Transaction()], timestamp: Date().timeIntervalSince1970, difficulty: 5000, nonce: 0, hash: Data())
            miner.mineBlock(block: newBlock) { foundBlock in
                miner.blockFound(block: foundBlock) //Update state, print output
                
                DispatchQueue.main.async {
                    self.mine()
                }

            }
            
        
    }
    
}

not an issue - fyi blockchain-demo

this demo on bitcoin (part 1/2) showcases a simple blockchain - I think this code base could leverage some of the ui stuff to push things along.
https://anders.com/blockchain/

I try to stay away from javascript like the plague - but code is written in jade.

screen shot 2018-01-10 at 10 24 17 am

68747470733a2f2f696d672e796f75747562652e636f6d2f76692f5f3136306f4d7a626c59382f302e6a7067
https://github.com/anders94/blockchain-demo

https://www.youtube.com/watch?v=_160oMzblY8&feature=youtu.be

probably any ui stuff should be done via api - I'm thinking ios / uitableviews using grpc or web json.
Need to expose api.

error: 'openssl/conf.h' file not found

none of these answers helped.
https://stackoverflow.com/questions/43415106/openssl-conf-h-file-not-found-error-on-macos-sierra

am using conda.

➜ VaporCoin git:(master) which openssl
/Users/johndpope/miniconda3/bin/openssl

could this help?
https://github.com/IBM-Swift/OpenSSL

I think a simple makefile with one liner does solve problem - or just add to readme.
brew install openssl

swift build -Xswiftc -I/usr/local/opt/openssl/include -Xlinker -L/usr/local/opt/openssl/lib
swift package -Xswiftc -I/usr/local/opt/openssl/include -Xlinker -L/usr/local/opt/openssl/lib generate-xcodeproj

 .build/debug/Run

linting - fyi

If you highlight all code - it's possible to auto indent swift
This could be super-ceded with special linting program but nice when working with many developers who each have their own style of indents.

eg.

screen shot 2018-01-10 at 2 58 34 pm

exploration - grpc service + protobuffers

one path forward / (my preferred option)
@zeptochain has defined these protobuffer files which outline bitcoin models.
https://github.com/zeptochain/bitcoin-proto/blob/master/proto/bitcoin-3.proto

// Bitcoin Protocol
// Third swag
// Version breaking out Bitcoin Script as a Protobuf

syntax = "proto3";
package bitcoin;

message Message {
	enum Command {
		VERSION = 0;
		VERACK = 1;
		ADDR = 2;
		INV = 3;
		GET_DATA = 4;
		NOT_FOUND = 5;
		GET_BLOCKS = 6;
		GET_HEADERS = 7;
		TX = 8;
		BLOCK = 9;
		HEADERS = 10;
		GET_ADDR = 11;
		MEMPOOL = 12;
		PING = 13;
		PONG = 14;
		REJECT = 15;
		ALERT = 16;
		FILTER_LOAD = 17;
		FILTER_ADD = 18;
		FILTER_CLEAR = 19;
		MERKLE_BLOCK = 20;
	}
	fixed32 magic = 1 [default = 3652501241]; // Transmitted as 0xF9BEB4D9 in NBO
	Command command = 2;
	uint32 payload_length = 3;
	uint32 checksum = 4;
	bytes payload = 5;
}

message Block {
	uint32 version = 1 [default = 2];
	bytes previous_block = 2;
	bytes merkle_root = 3;
	uint32 timestamp = 4;
	uint32 bits = 5;
	uint32 nonce = 6;
	Coinbase coinbase = 7;
	repeated Transaction transactions = 8;
}

message Coinbase {
	uint32 version = 1 [default = 1];
	CoinbaseInput input = 2;
	repeated TransactionOutput = 3;
}

message CoinbaseInput {
	uint32 block_height = 1;
	bytes miner_data = 2;
	sint32 sequence = 3;
}

message Transaction {
	uint32 version = 1 [default = 1];
	repeated TransactionInput inputs = 2;
	repeated TransactionOutput outputs = 3;
	uint32 lock_time = 4;
}

message Operation {
	enum Code {
		option allow_alias = true;
		OP_FALSE = 0;
		OP_0 = 0;
		OP_PUSH1 = 1;
		OP_PUSH2 = 2;
		OP_PUSH3 = 3;
		OP_PUSH4 = 4;
		OP_PUSH5 = 5;
		OP_PUSH6 = 6;
		OP_PUSH7 = 7;
		OP_PUSH8 = 8;
		OP_PUSH9 = 9;
		OP_PUSH10 = 10;
		OP_PUSH11 = 11;
		OP_PUSH12 = 12;
		OP_PUSH13 = 13;
		OP_PUSH14 = 14;
		OP_PUSH15 = 15;
		OP_PUSH16 = 16;
		OP_PUSH17 = 17;
		OP_PUSH18 = 18;
		OP_PUSH19 = 19;
		OP_PUSH20 = 20;
		OP_PUSH21 = 21;
		OP_PUSH22 = 22;
		OP_PUSH23 = 23;
		OP_PUSH24 = 24;
		OP_PUSH25 = 25;
		OP_PUSH26 = 26;
		OP_PUSH27 = 27;
		OP_PUSH28 = 28;
		OP_PUSH29 = 29;
		OP_PUSH30 = 30;
		OP_PUSH31 = 31;
		OP_PUSH32 = 32;
		OP_PUSH33 = 33;
		OP_PUSH34 = 34;
		OP_PUSH35 = 35;
		OP_PUSH36 = 36;
		OP_PUSH37 = 37;
		OP_PUSH38 = 38;
		OP_PUSH39 = 39;
		OP_PUSH40 = 40;
		OP_PUSH41 = 41;
		OP_PUSH42 = 42;
		OP_PUSH43 = 43;
		OP_PUSH44 = 44;
		OP_PUSH45 = 45;
		OP_PUSH46 = 46;
		OP_PUSH47 = 47;
		OP_PUSH48 = 48;
		OP_PUSH49 = 49;
		OP_PUSH50 = 50;
		OP_PUSH51 = 51;
		OP_PUSH52 = 52;
		OP_PUSH53 = 53;
		OP_PUSH54 = 54;
		OP_PUSH55 = 55;
		OP_PUSH56 = 56;
		OP_PUSH57 = 57;
		OP_PUSH58 = 58;
		OP_PUSH59 = 59;
		OP_PUSH60 = 60;
		OP_PUSH61 = 61;
		OP_PUSH62 = 62;
		OP_PUSH63 = 63;
		OP_PUSH64 = 64;
		OP_PUSH65 = 65;
		OP_PUSH66 = 66;
		OP_PUSH67 = 67;
		OP_PUSH68 = 68;
		OP_PUSH69 = 69;
		OP_PUSH70 = 70;
		OP_PUSH71 = 71;
		OP_PUSH72 = 72;
		OP_PUSH73 = 73;
		OP_PUSH74 = 74;
		OP_PUSH75 = 75;
		OP_PUSHDATA = 76;
		OP_PUSHDATA2 = 77;
		OP_PUSHDATA4 = 78;
		OP_1NEGATE = 79;
		OP_RESERVED = 80;
		OP_TRUE = 81;
		OP_1 = 81;
		OP_2 = 82;
		OP_3 = 83;
		OP_4 = 84;
		OP_5 = 85;
		OP_6 = 86;
		OP_7 = 87;
		OP_8 = 88;
		OP_9 = 89;
		OP_10 = 90;
		OP_11 = 91;
		OP_12 = 92;
		OP_13 = 93;
		OP_14 = 94;
		OP_15 = 95;
		OP_16 = 96;
		OP_NOP = 97;
		OP_VER = 98;
		OP_IF = 99;
		OP_NOTIF = 100;
		OP_VERIF = 101;
		OP_VERNOTIF = 102;
		OP_ELSE = 103;
		OP_ENDIF = 104;
		OP_VERIFY = 105;
		OP_RETURN = 106;
		OP_TOALTSTACK = 107;
		OP_FROMALTSTACK = 108;
		OP_2DROP = 109;
		OP_2DUP = 110;
		OP_3DUP = 111;
		OP_2OVER = 112;
		OP_2ROT = 113;
		OP_2SWAP = 114;
		OP_IFDUP = 115;
		OP_DEPTH = 116;
		OP_DROP = 117;
		OP_DUP = 118;
		OP_NIP = 119;
		OP_OVER = 120;
		OP_PICK = 121;
		OP_ROLL = 122;
		OP_ROT = 123;
		OP_SWAP = 124;
		OP_TUCK = 125;
		OP_CAT = 126;
		OP_SUBSTR = 127;
		OP_LEFT = 128;
		OP_RIGHT = 129;
		OP_SIZE = 130;
		OP_INVERT = 131;
		OP_AND = 132;
		OP_OR = 133;
		OP_XOR = 134;
		OP_EQUAL = 135;
		OP_EQUALVERIFY = 136;
		OP_RESERVED1 = 137;
		OP_RESERVED2 = 138;
		OP_1ADD = 139;
		OP_1SUB = 140;
		OP_2MUL = 141;
		OP_2DIV = 142;
		OP_NEGATE = 143;
		OP_ABS = 144;
		OP_NOT = 145;
		OP_0NOTEQUAL = 146;
		OP_ADD = 147;
		OP_SUB = 148;
		OP_MUL = 149;
		OP_DIV = 150;
		OP_MOD = 151;
		OP_LSHIFT = 152;
		OP_RSHIFT = 153;
		OP_BOOLAND = 154;
		OP_BOOLOR = 155;
		OP_NUMEQUAL = 156;
		OP_NUMEQUALVERIFY = 157;
		OP_NUMNOTEQUAL = 158;
		OP_LESSTHAN = 159;
		OP_GREATERTHAN = 160;
		OP_LESSTHANOREQUAL = 161;
		OP_GREATERTHANOREQUAL = 162;
		OP_MIN = 163;
		OP_MAX = 164;
		OP_WITHIN = 165;
		OP_RIPEMD160 = 166;
		OP_SHA1 = 167;
		OP_SHA256 = 168;
		OP_HASH160 = 169;
		OP_HASH256 = 170;
		OP_CODESEPARATOR = 171;
		OP_CHECKSIG = 172;
		OP_CHECKSIGVERIFY = 173;
		OP_CHECKMULTISIG = 174;
		OP_CHECKMULTISIGVERIFY = 175;
		OP_NOP1 = 176;
		OP_NOP2 = 177;
		OP_NOP3 = 178;
		OP_NOP4 = 179;
		OP_NOP5 = 180;
		OP_NOP6 = 181;
		OP_NOP7 = 182;
		OP_NOP8 = 183;
		OP_NOP9 = 184;
		OP_NOP10 = 185;
// Opcodes 186-252 are not defined
// Pseudo-words:
//		OP_PUBKEYHASH = 253;
//		OP_PUBKEY = 254;
//		OP_INVALIDOPCODE = 255;
	}
	Code opcode = 1;
	bytes data = 2;
}

message Script {
	repeated Operation operations = 1;
}

message TransactionInput {
	bytes outpoint_ref = 1;
	uint32 outpoint_index = 2;
	Script sig_script = 3;
	sint32 sequence = 4;
}

message TransactionOutput {
	uint32 value = 1;
	Script pk_script = 2;
}

message NetAddress {
	uint32 timestamp = 1;
	uint64 services = 2;
	bytes ip_address = 3;
	uint32 port = 4 [default = 8333];
}

message InventoryVector {
	enum VectorType {
		ERROR = 0;
		TRANSACTION = 1;
		BLOCK = 2;
		FILTERED_BLOCK = 3;
	}
	VectorType type = 1;
	bytes hash_reference = 2;
}

message Version {
	uint32 version = 1;
	uint64 services = 2;
	uint64 timestamp = 3;
	NetAddress addr_to = 4;
	NetAddress addr_from = 5;
	uint64 nonce = 6;
	string user_agent = 7;
	uint32 start_height = 8;
	bool relay = 9;
}

message Verack { }

message Addr {
	repeated NetAddress address_list = 1;
}

message Inv {
	repeated InventoryVector vectors = 1;
}

message GetData {
	repeated InventoryVector vectors = 1;
}

message NotFound {
	repeated InventoryVector vectors = 1;
}

message GetBlocks {
	uint32 version = 1;
	repeated bytes block_locator_hashes = 2;
	bytes hash_stop = 3;
}

message GetHeaders {
	uint32 version = 1;
	repeated bytes block_locator_hashes = 2;
	bytes hash_stop = 3;
}

message GetAddr { }

message Mempool { }

message Ping {
	uint64 nonce = 1;
}

message Pong {
	uint64 nonce = 1;
}

message Alert {
	bytes payload = 1;
	bytes signature = 2;
}

message Reject {
	enum Reason {
		UNDEFINED = 0;
		MALFORMED = 1;
		INVALID = 2;
		OBSOLETE = 3;
		DUPLICATE = 4;
		NONSTANDARD = 5;
		DUST = 6;
		INSUFFIENT_FEE = 7;
		CHECKPOINT = 8;
	}
	string message = 1;
	Reason ccode = 2;
}

message FilterLoad {
	bytes filter = 1;
	uint32 number_of_hash_functions = 2;
	uint32 tweak_nonce = 3;
	uint32 flags = 4;
}

message FilterAdd {
	bytes data = 1;
}

message FilterClear { }

message MerkleBlock {
	uint32 version = 1 [default = 2];
	bytes previous_block = 2;
	bytes merkle_root = 3;
	uint32 timestamp = 4;
	uint32 bits = 5;
	uint32 nonce = 6;
	uint32 total_transactions = 7;
	repeated bytes hashes = 8;
	bytes flags = 9;
}

message NodeState {
	bytes genesis_block = 1;
	bytes current_block = 2;
	uint32 block_height = 3;
}

there's currently no service class - meaning that there's no interoperability defined between services. but I'm thinking this could accelerate fleshing out models.

I created a batch file to do a bunch of things / down grpc /
https://github.com/nubbel/swift-tensorflow/blob/master/RUNME.sh

https://github.com/nubbel/swift-tensorflow

once you have a proto buffer layer defined -
then the way services can exchange data is very straightforward
https://github.com/nubbel/swift-tensorflow/tree/master/Sources

this is a grpc service layer demo
https://github.com/culumn/gRPC-Demo-Server

note inside the proto file there is some service code -

https://github.com/culumn/gRPC-Demo-Server/blob/master/Sources/user.proto

service UserService {
  // CREATE
  rpc Create(CreateRequest) returns (CreateResponse);

  // READ
  rpc Get(GetRequest) returns (GetResponse);
  rpc GetAll(GetAllRequest) returns (GetAllResponse);

  // UPDATE
  rpc Update(UpdateRequest) returns (UpdateResponse);

  // DELETE
  rpc Delete(DeleteRequest) returns (DeleteResponse);
}

with this defined - a service layer can be scaffolded up in minutes.
will keep digging on github for any other grpc + bitcoin service that may help pave the way.

Implement fractional difficulty

Swift can't deal with 256 bit UInts natively, so figure out how to implement this.
Without fractional difficulty, difficulty can only double or halve, which is inconvenient given difficulty will be adjusted hourly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.