-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
224 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package blockchain | ||
|
||
// BlockHeader contains metadata about a block | ||
import ( | ||
"crypto/sha256" | ||
"encoding/binary" | ||
"encoding/gob" | ||
"io" | ||
) | ||
|
||
// BlockHeader contains metadata about a block | ||
type BlockHeader struct { | ||
blockNumber uint32 | ||
lastBlock Hash | ||
miner Wallet | ||
} | ||
|
||
// Marshal converts a BlockHeader to a byte slice | ||
func (bh *BlockHeader) Marshal() []byte { | ||
buf := []byte{} | ||
binary.LittleEndian.PutUint32(buf, bh.blockNumber) | ||
for _, b := range bh.lastBlock { | ||
buf = append(buf, b) | ||
} | ||
buf = append(buf, bh.miner.Marshal()...) | ||
return buf | ||
} | ||
|
||
// Block represents a block in the blockchain. Contains transactions and header metadata. | ||
type Block struct { | ||
BlockHeader | ||
transactions []*Transaction | ||
} | ||
|
||
// Marshal converts a Block to a byte slice | ||
func (b *Block) Marshal() []byte { | ||
buf := b.BlockHeader.Marshal() | ||
for _, t := range b.transactions { | ||
buf = append(buf, t.Marshal()...) | ||
} | ||
return buf | ||
} | ||
|
||
// Encode writes the marshalled block to the given io.Writer | ||
func (b *Block) Encode(w io.Writer) { | ||
gob.NewEncoder(w).Encode(b) | ||
} | ||
|
||
// Decode reads the marshalled block from the given io.Reader | ||
func (b *Block) Decode(r io.Reader) { | ||
gob.NewDecoder(r).Decode(b) | ||
} | ||
|
||
// Hash computes and returns the SHA256 hash of the block | ||
func (b *Block) Hash() Hash { | ||
return sha256.Sum256(b.Marshal()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package blockchain | ||
|
||
import ( | ||
"encoding/gob" | ||
"io" | ||
) | ||
|
||
// Hash represents a 256-bit hash of a block or transaction | ||
type Hash [32]byte | ||
|
||
// BlockChain represents a linked list of blocks | ||
type BlockChain struct { | ||
blocks []*Block | ||
head Hash | ||
} | ||
|
||
// Encode writes the marshalled blockchain to the given io.Writer | ||
func (bc *BlockChain) Encode(w io.Writer) { | ||
gob.NewEncoder(w).Encode(bc) | ||
} | ||
|
||
// Decode reads the marshalled blockchain from the given io.Reader | ||
func (bc *BlockChain) Decode(r io.Reader) { | ||
gob.NewDecoder(r).Decode(bc) | ||
} | ||
|
||
// ValidTransaction checks whether a transaction is valid, assuming the blockchain is valid. | ||
func (bc *BlockChain) ValidTransaction(t *Transaction) bool { | ||
// Find the transaction input (I) in the chain (by hash) | ||
// Check that output to sender in I is equal to outputs in T | ||
// Verify signature of T | ||
return false | ||
} | ||
|
||
// ValidBlock checks whether a block is valid | ||
func (bc *BlockChain) ValidBlock(b *Block) bool { | ||
for _, t := range b.transactions { | ||
if !bc.ValidTransaction(t) { | ||
return false | ||
} | ||
} | ||
// Check that block number is one greater than last block | ||
// Check that hash of last block is correct | ||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package blockchain | ||
|
||
import ( | ||
"crypto/sha256" | ||
"encoding/binary" | ||
) | ||
|
||
// TxHashPointer is a reference to a transaction on the blockchain. | ||
type TxHashPointer struct { | ||
blockNumber uint32 | ||
hash Hash | ||
} | ||
|
||
// Marshal converts a TxHashPointer to a byte slice | ||
func (thp TxHashPointer) Marshal() []byte { | ||
buf := []byte{} | ||
binary.LittleEndian.PutUint32(buf, thp.blockNumber) | ||
for _, b := range thp.hash { | ||
buf = append(buf, b) | ||
} | ||
return buf | ||
} | ||
|
||
// TxOutput defines an output to a transaction | ||
type TxOutput struct { | ||
amount uint64 | ||
recipient Wallet | ||
} | ||
|
||
// Marshal converts a TxOutput to a byte slice | ||
func (to TxOutput) Marshal() []byte { | ||
buf := []byte{} | ||
binary.LittleEndian.PutUint64(buf, to.amount) | ||
buf = append(buf, to.recipient.Marshal()...) | ||
return buf | ||
} | ||
|
||
// TxBody contains all relevant information about a transaction | ||
type TxBody struct { | ||
sender Wallet | ||
input TxHashPointer | ||
outputs []TxOutput | ||
} | ||
|
||
// Marshal converts a TxBody to a byte slice | ||
func (tb TxBody) Marshal() []byte { | ||
buf := tb.sender.Marshal() | ||
buf = append(buf, tb.input.Marshal()...) | ||
for _, out := range tb.outputs { | ||
buf = append(buf, out.Marshal()...) | ||
} | ||
return buf | ||
} | ||
|
||
// Transaction contains a TxBody and a signature verifying it | ||
type Transaction struct { | ||
TxBody | ||
sig Signature | ||
} | ||
|
||
// Marshal converts a Transaction to a byte slice | ||
func (t *Transaction) Marshal() []byte { | ||
buf := t.TxBody.Marshal() | ||
buf = append(buf, t.sig.Marshal()...) | ||
return buf | ||
} | ||
|
||
// Hash returns the SHA256 hash of a transaction | ||
func (t *Transaction) Hash() Hash { | ||
return sha256.Sum256(t.Marshal()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package blockchain | ||
|
||
import ( | ||
"crypto/ecdsa" | ||
"crypto/elliptic" | ||
"crypto/rand" | ||
"fmt" | ||
"math/big" | ||
) | ||
|
||
// The curve we use for our ECC crypto. | ||
var curve = elliptic.P256() | ||
|
||
// Wallet represents a Cumulus wallet address in the blockchain. | ||
type Wallet ecdsa.PublicKey | ||
|
||
// Signature represents a signature of a transaction. | ||
type Signature struct { | ||
X big.Int | ||
Y big.Int | ||
} | ||
|
||
// Marshal converts a signature to a byte slice | ||
func (s *Signature) Marshal() []byte { | ||
return append(s.X.Bytes(), s.Y.Bytes()...) | ||
} | ||
|
||
// New creates a new Wallet backed by a ECC key pair. Uses system entropy. | ||
func newWallet() (*Wallet, error) { | ||
k, err := ecdsa.GenerateKey(curve, rand.Reader) | ||
if err != nil { | ||
return nil, err | ||
} | ||
pk := Wallet(k.PublicKey) | ||
return &pk, nil | ||
} | ||
|
||
// String returns a human-readable string representation of a wallet | ||
func (w *Wallet) String() string { | ||
return fmt.Sprintf("%x-%x", w.X, w.Y) | ||
} | ||
|
||
// Marshal converts the Wallet to a byte slice | ||
func (w *Wallet) Marshal() []byte { | ||
return elliptic.Marshal(curve, w.X, w.Y) | ||
} | ||
|
||
// Equals checks whether two wallets are the same. | ||
func (w *Wallet) Equals(other *Wallet) bool { | ||
return w.X.Cmp(other.X) == 0 && w.Y.Cmp(other.Y) == 0 | ||
} |