Transactions and Bookkeeping

Source: Internet
Author: User

Tags: Whether iterator end wal rom process Roo int Walle

Trading Mechanism:
1. Blockchain can store transaction results safely and reliably
2, in the blockchain, once the transaction is created, no one can modify or delete
3, the transaction by some input and some output combination
4. For a new transaction, its input will refer to the output of the previous transaction
5, the output of the transaction, that is, the actual location of bitcoin storage
6. Exceptions:
1. Some outputs are not associated with an input (not yet used)
2, the input of a transaction can refer to the output of the previous multiple transactions
3, an input must refer to an output

Mining->a to get 10 bitcoins through mining

Input is empty, output is a get 10 bitcoin

Transfer->a to B to pay 3 Bitcoins:

Find a unused transaction (the total is enough to pay)

Then a is found out of these trades as input list, if there is the rest will be a change process (a will have a 7 bitcoin output)

and B will have a 3 bitcoin output.

These inputs and outputs are stored in the chain as data for the new chunk

Find out if someone is not using the trading algorithm:

Starting with the newest head of the chain, finding the input that belongs to someone, filtering out the output that is linked to these inputs is the person's unused trade (balance)

Transaction.go

Package Coreimport ("FMT" "bytes" "Encoding/gob" "Log" "crypto/sha256" "Encoding/hex") const subsidy = 10//transactions Represents a bitcointype Transaction struct {ID []bytevin []txinputvout] []txoutput}//txinput represents a Transaction Inpu Ttype txinput struct {Txid []bytevout intscriptsig String}//canunlockoutputwith checks whether the address initiated the T Ransactionfunc (in *txinput) Canunlockoutputwith (Unlockingdata string) bool {return in. Scriptsig = = Unlockingdata}//txoutput Represents a transaction OutputType txoutput struct {Value Intscriptpubkey St Ring}//setid sets ID of a Transactionfunc (TX *transaction) SetID () {var encoder bytes. Buffervar hash [32]byteenc: = Gob. Newencoder (&encoder) Err: = Enc. Encode (TX) If err! = Nil {log. Panic (err)}hash = sha256. SUM256 (encoder.  Bytes ()) Tx.id = Hash[:]}//newcoinbasetx Create a new Coinbase Transactionfunc newcoinbasetx (to, data string) *transaction {if data = = "" {data = FMT. Sprintf ("Reward to%s", to)}txin: = txinput{[]byte{},-1, DAta}txout:= Txoutput{subsidy, To}tx: = Transaction{nil, []txinput{txin}, []txoutput{txout}}tx. SetID () Return &tx}//canbeunlockedwith checks if the output can be unlocked and the provided Datafunc (out *txoutput) Canbeunlockedwith (Unlockingdata string) bool {return out. Scriptpubkey = = Unlockingdata}//iscoinbase checks whether the transaction is Coinbasefunc (TX transaction) Iscoinbase () Bo OL {return Len (TX. Vin) = = 1 && len (TX. Vin[0]. TXID) = = 0 && tx. Vin[0]. Vout = = -1}//newutxotransaction Creates a new Transactionfunc newutxotransaction (from,to string, amount int, BC *blockchai N) *transaction {var inputs []txinputvar outputs []txoutputacc,validoutputs: = BC. Findspendableoutputs (from, amount) if ACC < amount {log. Panic ("Error:not enough Funds")}//build a list of inputsfor txid,outs: = Range validoutputs {txid,err: = hex. Decodestring (TXID) if err! = Nil {log. Panic (Err)}for _,out: = Range Outs {input: = txinput{txid,out, from}inputs = append (inputs,input)}}//build a LisT of outputsoutputs = append (outputs, txoutput{amount,to}) if acc > amount {outputs = append (outputs, Txoutput{acc-amo UNT, from})}tx: = Transaction{nil, inputs, outputs}tx. SetID () return &AMP;TX}

Cli.go

Package Coreimport ("FMT", "OS" "Flag" "Log" "StrConv")//cli responsible for processing command line Argumentstype CLI struct {}func (CLI *cli) Createblockchain (address string) {BC: = Createblockchain (address) defer BC. Db.close () fmt. Println ("Done")}func (CLI *cli) getbalance (address string) {BC: = Newblockchain (address) defer BC. Db.close () Balance: = 0UTXOs: = BC. Findutxo (address) for _,out: = Range Utxos {balance + = out. Value}fmt. Printf ("Balance of '%s ': '%d '", address, Balance)}func (CLI *cli) send (from, to string, amount int) {BC: = Newblockchain ( from) defer BC. Db.close () tx: = newutxotransaction (FROM,TO,AMOUNT,BC) BC. Mineblock ([]*transaction{tx}) fmt. Println ("Success")}func (CLI *cli) printusage () {fmt. Println ("Usage:") fmt. Println ("Getbalance-address address-get Balance of Address") FMT. Println ("Createblockchain-address address-create a Blockchain" + "and send Genesis block reward to address") FMT. Println ("Printchain-print all the blocks of the blockchain") fmt. Println ("Send-from FROM-to to-amount amount-send amount of "+" coin from the Address to ")}func (CLI *cli) Validateargs () {If Len (OS. Args) < 2 {cli.printusage () OS. Exit (1)}}func (CLI *cli) Printchain () {BC: = Newblockchain ("") defer BC. Db.close () BCI: = BC. Iterator () for {block: = BCI. Next () fmt. Printf ("Prev Hash:%x\n", block. Prevblockhash) fmt. Printf ("Hash:%x\n", block. Hash) Pow: = newproofofwork (block) fmt. Printf ("Pow:%s\n", StrConv. Formatbool (POW. Validate ())) Fmt. Println () If Len (block. Prevblockhash) = = 0 {break}}}//run Parses command line arguments and process Commandsfunc (CLI *cli) Run () {cli.validatear GS () Getbalancecmd: = flag. Newflagset ("GetBalance", flag. Exitonerror) Printchaincmd: = flag. Newflagset ("Printchain", flag. Exitonerror) Sendcmd: = flag. Newflagset ("Send", flag. Exitonerror) Createblockchaincmd: = flag. Newflagset ("Createblockchain", flag. Exitonerror) Getbalanceaddress: = getbalancecmd.string ("Address", "", "the Address" + "to get balance for") Createblockchainaddress: = Createblockchaincmd.striNg ("Address", "", "the address to send Genesis Block award to") Sendfrom: = Sendcmd.string ("from", "", "Source wallet Address ") SendTo: = Sendcmd.string (" To "," "", "Destination wallet Address") Sendamount: = Sendcmd.int ("Amount", 0, "amount to send") Switch OS. ARGS[1] {case "Createblockchain": Err: = Createblockchaincmd.parse (OS. Args[2:]) if err! = Nil {log. Panic (Err)}case "Printchain": Err: = Printchaincmd.parse (OS. Args[2:]) if err! = Nil {log. Panic (Err)}case "getbalance": Err: = Getbalancecmd.parse (OS. Args[2:]) if err! = Nil {log. Panic (Err)}case "send": Err: = Sendcmd.parse (OS. Args[2:]) if err! = Nil {log. Panic (Err)}default:cli.printusage () OS. Exit (1)}if getbalancecmd.parsed () {if *getbalanceaddress = = "" {getbalancecmd.usage () OS. Exit (1)}cli.getbalance (*getbalanceaddress)}if createblockchaincmd.parsed () {if *createblockchainaddress = = "" { Createblockchaincmd.usage () OS. Exit (1)}cli.createblockchain (*createblockchainaddress)}if sendcmd.parsed () {if *sendfrom = = "" | | *sendto = = "" | | *sendamount <=0 {sendcmd.usage () OS. Exit (1)}cli.send (*sendfrom, *sendto, *sendamount)}if printchaincmd.parsed () {Cli.printchain ()}}

Blockchain.go

Package Coreimport ("Github.com/boltdb/bolt" "Log" "FMT" "OS" "Encoding/hex") const DBFile = "Blockchain.db" const Blockbucket = "blocks" Const GENESISCOINBASEDATA = "The time 03/jan/2009 Chancellor on brink of second bailout for bank"//b Lockchain keeps a sequence of blockstype BlockChain struct {tip []bytedb *bolt.          Db}//blockchainiterator is used to iterator over blockchain blockstype blockchainiterator struct {currenthash []bytedb *bolt. Db}//iteratorfunc (BC *blockchain) Iterator () *blockchainiterator {BCI: = &blockchainiterator{bc.tip, BC. Db}return Bci}//next returns next block starting from the Tipfunc (I *blockchainiterator) next () *block {var block *blocke RR: = I.db.view (func (TX *bolt). TX) Error {b: = tx. Bucket ([]byte (Blockbucket)) Encoderblock: = B.get (i.currenthash) block = Deserializeblock (Encoderblock) return nil}) if Err! = Nil {log. Panic (err)}i.currenthash = block. Prevblockhashreturn block}func Newblockchain (address string) *blockchain {if dbexists () = = False {fmt. Println ("No Blockchain exists, create one first") OS. Exit (1)}var tip []bytedb,err: = Bolt. Open (DBFile, 0600, nil) if err! = Nil {log. Panic (err)}err = db. Update (func (TX *bolt). TX) Error {db: = tx. Bucket ([]byte (blockbucket)) tip = db. Get ([]byte ("L")) return nil}) if err! = Nil {log. Panic (err)}BC: = Blockchain{tip, Db}return &bc}func dbexists () bool {if _,err: = OS. Stat (DBFile); Os. Isnotexist (Err) {return False}return True}//findutxo finds and returns all unspent transaction outputsfunc (BC *blockchain ) Findutxo (address string) []txoutput{var Utxos []txoutputunspenttransactions: = BC. Findunspenttransactions (address) for _,TX: = Range unspenttransactions {for _,out: = Range TX. Vout {if out. Canbeunlockedwith (address) {Utxos = append (Utxos, out)}}}return Utxos}//findspendableoutputs finds and returns unspent O Utputs to reference in Inputsfunc (BC *blockchain) findspendableoutputs (address string, amount int) (Int,map[string][]int {unspentoutputs: = Make (Map[string][]int) unspenttxs: = BC. FindunspenttraNsactions (address) Accumulated: = 0work:for _,tx: = range Unspenttxs{txid: = Hex. Encodetostring (tx.id) for outidx,out: = Range TX. Vout {if out. Canbeunlockedwith (address) && accumulated < Amount {accumulated + = out. VALUEUNSPENTOUTPUTS[TXID] = append (unspentoutputs[txid],outidx) if accumulated >= amount {break Work}}}}return Accumulated, Unspentoutputs}//findunspenttransactions Returns a list of transactions containing unspent outputsfunc (BC * BlockChain) findunspenttransactions (address string) []transaction {var unspenttxs []transactionspenttxos: = Make (map[ String][]int) BCI: = BC. Iterator () for {block: = BCI. Next () for _,tx: = range block. Transactions {txID: = hex. Encodetostring (tx.id) outputs:for outidx, out: = Range TX. Vout {//was The output spent?if spenttxos[txid]! = nil{for _,spentout: = Range Spenttxos[txid] {if spentout = = Outidx {con Tinue outputs}}}if out. Canbeunlockedwith (address) {Unspenttxs = append (unspenttxs,*tx)}}if TX. Iscoinbase () = = False {for _,in: = Range TX. VIn {if in. Canunlockoutputwith (address) {intxid: = hex. Encodetostring (in. TXID) Spenttxos[intxid] = append (Spenttxos[intxid], in. Vout)}}}if Len (block. Prevblockhash) = = 0 {Break}}return Unspenttxs}}//createblockchain create a new blockchain Dbfunc Createblockchain ( Address string) *blockchain {if dbexists () {fmt. Println ("Blockchain already exsits.") Os. Exit (1)}var tip []bytedb,err: = Bolt. Open (DBFile, 0600, nil) if err! = Nil {log. Panic (err)}err = db. Update (func (TX *bolt). TX) Error {CBTX: = Newcoinbasetx (address, genesiscoinbasedata) Genesis: = Newgenesisblock (CBTX) B,err: = Tx. Createbucket ([]byte (Blockbucket)) if err! = Nil {log. Panic (err)}err = B.put (Genesis. Hash, Genesis. Serialize ()) if err! = Nil {log. Panic (err)}err = B.put ([]byte ("L"), Genesis. Hash) If err! = Nil {log. Panic (err)}tip = Genesis. Hashreturn nil}) if err! = Nil {log. Panic (err)}BC: = Blockchain{tip, Db}return &bc}//mineblock mines a new block with the provided Transactionsfunc (BC *B Lockchain) mineblock (transaction []*transaction) {var Lasthash []byteerr: = BC. Db.view (func (TX *bolt). TX) Error {b: = tx. Bucket ([]byte (blockbucket)) Lasthash = B.get ([]byte ("L")) return nil}) if err! = Nil {log. Panic (err)}newblock: = Newblock (transaction,lasthash) err = BC. Db.update (func (TX *bolt). TX) Error {b: = tx. Bucket ([]byte (Blockbucket)) Err: = B.put (Newblock.hash, Newblock.serialize ()) if err! = Nil {log. Panic (err)}err = B.put ([]byte ("L"), Newblock.hash) if err! = Nil {log. Panic (err)}bc.tip = Newblock.hashreturn Nil}) if err! = Nil {log. Panic (ERR)}}

Main.go

Package Mainimport "Core" Func main () {cli: = core. Cli{}cli. Run ()}

Block.go

Package Coreimport ("Time" "bytes" "Encoding/gob" "Log" "crypto/sha256")//block keeps block Headertype block struct {          Timestamp Int64//Block creation time transactions []*transaction//chunk contains data prevblockhash []byte///previous chunk hash value hashes  []byte//Chunk's own hash value, used to verify chunk data valid Nonce int//record work proof used digital}func (b *block) Serialize () []byte {var result bytes. Bufferencoder: = Gob. Newencoder (&result) Err: = Encoder. Encode (b) if err! = Nil {log. Panic (ERR)}return result. Bytes ()}func deserializeblock (d []byte) *block {var Block blockdecoder: = Gob. Newdecoder (bytes. Newreader (d)) Err: = decoder. Decode (&block) if err! = Nil {log. Panic (ERR)}return &block}//newblock Create and returns Blockfunc Newblock (transactions []*transaction, Prevblockhash []byte] *block {Block: = &block{timestamp:time. Now (). Unix (), Transactions:transactions,prevblockhash:prevblockhash,hash: []byte{},nonce:0,}pow: = NewProofO Fwork (block)//new work proof Nonce,hash: = Pow.  Run ()Perform proof of work (mining) block. Hash = Hashblock. Nonce = Noncereturn Block}//newgenesisblock Create and returns Genesis Blockfunc Newgenesisblock (Coinbase *transaction) * Block {return Newblock ([]*transaction{coinbase}, []byte{})}//hashtransactions returns a hash of the Transaction in the Blo Ckfunc (b *block) hashtransactions () []byte {var txhashs [][]bytevar Txhash [32]bytefor _,tx: = Range B.transactions {txHa SHS = Append (Txhashs, tx.id)}txhash = sha256. Sum256 (bytes. Join (TXHASHS, []byte{})) return txhash[:]}

Proofofwork.go

Package Coreimport ("math" "Math/big" "FMT" "crypto/sha256" "bytes") var (maxnonce = math). MaxInt64) Const Targetbits = 16//proofofwork represents a proof-of-worktype proofofwork struct {block *blocktarget *big. Int}//newproofofwork builds and returns a Proofofworkfunc newproofofwork (b *block) *proofofwork {target: = big. Newint (1) target. Lsh (Target,uint (256-targetbits)) Pow: = &proofofwork{b, Target}return pow}func (Pow *proofofwork) prepareData ( nonce int) []byte {data: = bytes. Join ([][]byte{pow.block.prevblockhash,pow.block.hashtransactions (), Inttohex (Int64 (Pow.block.Timestamp)), Inttohex (Int64 (targetbits)), Inttohex (Int64 (nonce)),},[]byte{}, return Data}func (Pow *proofofwork) Run (int, [] byte) {var hashint big. Intvar hash [32]bytenonce: = 0fmt. Printf ("Mining a new block") for Nonce < maxnonce {data: = Pow.preparedata (nonce) hash = sha256. Sum256 (data) fmt. Printf ("\r%x", hash) hashint.setbytes (hash[:]) if hashint.cmp (pow.target) = =-1 {break}else{nonce++}}fmt. Print ("\ n") return nonce,hash[:]}func (Pow *proofofwork) Validate () bool {var hashint big. Intdata: = Pow.preparedata (pow.block.Nonce) Hash: = sha256. Sum256 (data) hashint.setbytes (hash[:]) IsValid: = hashint.cmp (pow.target) = = -1return IsValid}

  

Transactions and Bookkeeping

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

Tags Index: