Skip to content

Commit

Permalink
Completed tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyler King committed Mar 24, 2019
1 parent 68720fc commit 4c5d0bf
Show file tree
Hide file tree
Showing 6 changed files with 354 additions and 48 deletions.
7 changes: 7 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Copyright (C) 2019 Tyler King <tyler@ohmybrew.com>

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 changes: 25 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
# GoChain

[![Build Status](https://secure.travis-ci.org/ohmybrew/gochain.png?branch=master)](http://travis-ci.org/ohmybrew/gochain)
[![Coverage Status](https://coveralls.io/repos/github/ohmybrew/gochain/badge.svg?branch=master)](https://coveralls.io/github/ohmybrew/gochain?branch=master)

Port of my Blockchain-PHP library to a Golang. The speed is roughly 90% faster.

*Note: Not yet completed.*

# Usage
## Usage

```go
package main

import (
gc "github.com/ohmybrew/gochain"
gc "github.com/ohmybrew/gochain"
"fmt"
)

// ...
// New chain.
c := new(gc.Chain)

// Add two blocks, mine them. Difficulty of "2".
dif := 2
blk1 := c.BuildBlock(dif, "One")
blk2 := c.BuildBlock(dif, "Two")

blk1.Mine()
blk1.GenerateHash(true)
blk2.Mine()
blk2.GenerateHash(true)

fmt.Println("Chain is valid?", c.IsValid()); // See tests for more examples
```

# Testing
## Testing

*Note: Test not complete*
`bin/test` for test suite.

`bin/test` or `bin/cover` for coverage output.
`bin/cover` for test suite with coverage output.

# Notes
## LICENSE

All code is formatted with `gofmt -w .`.
This project is released under the MIT [license](https://github.com/ohmybrew/gochain/blob/master/LICENSE).
37 changes: 27 additions & 10 deletions block.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,31 @@ import (

// Reprecents a block.
type Block struct {
Previous *Block `json:"-"`
PreviousHash []byte `json:"previous_hash"`
Hash []byte `json:"hash"`
Index int `json:"index"`
Nonce int `json:"nonce"`
Difficulty int `json:"difficulty"`
Data string `json:"data"`
Timestamp time.Time `json:"timestamp"`
Previous *Block `json:"-"`
Hash []byte `json:"hash"`
Index int `json:"index"`
Nonce int `json:"nonce"`
Difficulty int `json:"difficulty"`
Data string `json:"data"`
Timestamp time.Time `json:"timestamp"`
}

// Marshal for JSON encode.
// Used to add "previous_hash" to the JSON output.
func (blk Block) MarshalJSON() ([]byte, error) {
// Create an alias to the block struct to prevent recursion.
type Alias Block

// Add our previous hash to the alias struct.
return json.Marshal(
struct {
PreviousHash []byte `json:"previous_hash"`
Alias
}{
PreviousHash: blk.Previous.Hash,
Alias: Alias(blk),
},
)
}

// Encodes the struct to JSON format.
Expand Down Expand Up @@ -109,8 +126,8 @@ func (blk Block) IsValid() bool {
if pb := blk.Previous; pb.IsMined() {
// Test previous block's index plus one, will equal this block's index.
// Test the hash of previous block's hash is what is set for this block's previous hash.
// Test this block's nonce is valid
if ((pb.Index + 1) == blk.Index) && bytes.Equal(pb.Hash, blk.PreviousHash) && blk.IsValidNonce() {
// Test this block's nonce is valid.
if ((pb.Index + 1) == blk.Index) && bytes.Equal(pb.Hash, blk.Previous.Hash) && blk.IsValidNonce() {
pok = true
} else {
pok = false
Expand Down
75 changes: 69 additions & 6 deletions block_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,70 @@ func TestBlockIsNotValid(t *testing.T) {
}
}

// Test the entire mined block can self validate with a full previous block.
func TestBlockValidatesWithPreviousBlock(t *testing.T) {
// Block 1
pb := new(Block)
blk := &Block{
Previous: pb,
Index: 1,
Difficulty: 1,
Data: "Hello World",
Timestamp: time.Now(),
}

blk.Mine()
blk.GenerateHash(true)

// Block 2
blk2 := &Block{
Previous: blk,
Index: 2,
Difficulty: 1,
Data: "Hellow World, Again",
Timestamp: time.Now(),
}

blk2.Mine()
blk2.GenerateHash(true)

if !blk.IsValid() || !blk2.IsValid() {
t.Errorf("Expected blocks to validate but failed")
}
}

// Test a bad previous block fails to validate.
func TestBlockIsNotValidWithPreviousBlock(t *testing.T) {
// Block 1
pb := new(Block)
blk := &Block{
Previous: pb,
Index: 1,
Difficulty: 1,
Data: "Hello World",
Timestamp: time.Now(),
}

blk.Mine()
blk.GenerateHash(true)

// Block 2
blk2 := &Block{
Previous: blk,
Index: 1, // Change the index
Difficulty: 1,
Data: "Hellow World, Again",
Timestamp: time.Now(),
}

blk2.Mine()
blk2.GenerateHash(true)

if blk2.IsValid() {
t.Errorf("Expected block to be invalid but result was valid")
}
}

// Create a plain unmined block for test use.
func createBlock() (blk *Block) {
// Create an empty previous block.
Expand All @@ -122,12 +186,11 @@ func createBlock() (blk *Block) {

// Create the block.
blk = &Block{
Previous: pb,
PreviousHash: pb.Hash,
Index: 1,
Difficulty: 1,
Data: "Hello World",
Timestamp: ts,
Previous: pb,
Index: 1,
Difficulty: 1,
Data: "Hello World",
Timestamp: ts,
}

return
Expand Down
53 changes: 29 additions & 24 deletions chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gochain

import (
"bytes"
"errors"
"time"
)

Expand All @@ -17,45 +18,45 @@ func (c Chain) Length() int {

// Gets the previous block relative to the provided index.
// If no available previous block is found, nil is returned
func (c Chain) PreviousBlock(i int) *Block {
func (c Chain) PreviousBlock(i int) (*Block, error) {
// Next index to target
ni := i - 1

if c.Length() > 0 && ni >= 0 {
// Previous block index is available, get it.
return c.Blocks[ni]
return c.Blocks[ni], nil
}

// No previous block, return empty.
return new(Block)
// No previous block.
return nil, errors.New("no previous block")
}

// Get the last block in the chain.
func (c Chain) LastBlock() *Block {
func (c Chain) LastBlock() (*Block, error) {
// Count the length of the chain.
ct := c.Length()

if ct > 0 {
// We can get the last block.
return c.Blocks[ct-1]
return c.Blocks[ct-1], nil
}

// No last block, return empty.
return new(Block)
// No last block.
return nil, errors.New("no last block")
}

// Get the first block in the chain.
func (c Chain) FirstBlock() *Block {
func (c Chain) FirstBlock() (*Block, error) {
// Count the length of the chain.
ct := c.Length()

if ct > 0 {
// We can get the last block.
return c.Blocks[0]
return c.Blocks[0], nil
}

// No first block, return empty.
return new(Block)
// No first block.
return nil, errors.New("no first block")
}

// Adds a block to the chain and returns the chain.
Expand All @@ -70,16 +71,19 @@ func (c *Chain) AddBlock(blk *Block) *Chain {
// The newly created block is returned and added to the chain.
func (c *Chain) BuildBlock(dif int, dat string) (blk *Block) {
// Get the last block
lb := c.LastBlock()
lb, err := c.LastBlock()
if err != nil {
// Make a empty block to use as previous.
lb = new(Block)
}

// Build the new block based on the previous block.
blk = &Block{
Previous: lb,
PreviousHash: lb.Hash,
Index: lb.Index + 1,
Timestamp: time.Now(),
Difficulty: dif,
Data: dat,
Previous: lb,
Index: lb.Index + 1,
Timestamp: time.Now(),
Difficulty: dif,
Data: dat,
}

// Add to the chain
Expand All @@ -88,17 +92,18 @@ func (c *Chain) BuildBlock(dif int, dat string) (blk *Block) {
return
}

// Checks if the blocks are the same (simple hash check).
func (c Chain) IsSameBlock(b1 *Block, b2 *Block) bool {
return bytes.Equal(b1.Hash, b2.Hash)
}

// Walks the chain to ensure all blocks are valid.
func (c Chain) IsValid() bool {
for _, blk := range c.Blocks {
if ok := blk.IsValid(); ok != true {
if ok := blk.IsValid(); !ok {
return false
}
}

return true
}

func (c Chain) IsSameBlock(b1 *Block, b2 *Block) bool {
return bytes.Equal(b1.Hash, b2.Hash)
}
Loading

0 comments on commit 4c5d0bf

Please sign in to comment.