1 package blockchain_test
2 3 import (
4 "fmt"
5 bits2 "github.com/p9c/p9/pkg/bits"
6 "github.com/p9c/p9/pkg/block"
7 "log"
8 "math/big"
9 "os"
10 "path/filepath"
11 12 "github.com/p9c/p9/pkg/blockchain"
13 "github.com/p9c/p9/pkg/chaincfg"
14 "github.com/p9c/p9/pkg/database"
15 _ "github.com/p9c/p9/pkg/database/ffldb"
16 )
17 18 // This example demonstrates how to create a new chain instance and use ProcessBlock to attempt to add a block to the
19 // chain. As the package overview documentation describes, this includes all of the Bitcoin consensus rules. This
20 // example intentionally attempts to insert a duplicate genesis block to illustrate how an invalid block is handled.
21 func ExampleBlockChain_ProcessBlock() {
22 // Create a new database to store the accepted blocks into. Typically this would be opening an existing database and
23 // would not be deleting and creating a new database like this, but it is done here so this is a complete working
24 // example and does not leave temporary files laying around.
25 dbPath := filepath.Join(os.TempDir(), "exampleprocessblock")
26 _ = os.RemoveAll(dbPath)
27 db, e := database.Create("ffldb", dbPath, chaincfg.MainNetParams.Net)
28 if e != nil {
29 log.Printf("Failed to create database: %v\n", e)
30 return
31 }
32 defer func() {
33 if e = os.RemoveAll(dbPath); E.Chk(e) {
34 }
35 }()
36 defer func() {
37 if e = db.Close(); E.Chk(e) {
38 }
39 }()
40 // Create a new BlockChain instance using the underlying database for the main bitcoin network. This example does
41 // not demonstrate some of the other available configuration options such as specifying a notification callback and
42 // signature cache. Also, the caller would ordinarily keep a reference to the median time source and add time values
43 // obtained from other peers on the network so the local time is adjusted to be in agreement with other peers.
44 chain, e := blockchain.New(
45 &blockchain.Config{
46 DB: db,
47 ChainParams: &chaincfg.MainNetParams,
48 TimeSource: blockchain.NewMedianTime(),
49 },
50 )
51 if e != nil {
52 log.Printf("Failed to create chain instance: %v\n", e)
53 return
54 }
55 // Process a block. For this example, we are going to intentionally cause an error by trying to process the genesis
56 // block which already exists.
57 genesisBlock := block.NewBlock(chaincfg.MainNetParams.GenesisBlock)
58 var isMainChain bool
59 var isOrphan bool
60 isMainChain, isOrphan, e = chain.ProcessBlock(
61 0, genesisBlock,
62 blockchain.BFNone, 0,
63 )
64 if e != nil {
65 log.Printf("Failed to process block: %v\n", e)
66 return
67 }
68 log.Printf("Block accepted. Is it on the main chain?: %v", isMainChain)
69 log.Printf("Block accepted. Is it an orphan?: %v", isOrphan)
70 // Output:
71 // Failed to process block: already have block 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
72 }
73 74 // This example demonstrates how to convert the compact "bits" in a block header which represent the target difficulty
75 // to a big integer and display it using the typical hex notation.
76 func ExampleCompactToBig() {
77 // Convert the bits from block 300000 in the main block chain.
78 bits := uint32(419465580)
79 targetDifficulty := bits2.CompactToBig(bits)
80 // Display it in hex.
81 fmt.Printf("%064x\n", targetDifficulty.Bytes())
82 // Output:
83 // 0000000000000000896c00000000000000000000000000000000000000000000
84 }
85 86 // This example demonstrates how to convert a target difficulty into the compact "bits" in a block header which
87 // represent that target difficulty .
88 func ExampleBigToCompact() {
89 // Convert the target difficulty from block 300000 in the main block
90 // chain to compact form.
91 t := "0000000000000000896c00000000000000000000000000000000000000000000"
92 targetDifficulty, success := new(big.Int).SetString(t, 16)
93 if !success {
94 fmt.Println("invalid target difficulty")
95 return
96 }
97 bits := bits2.BigToCompact(targetDifficulty)
98 fmt.Println(bits)
99 // Output:
100 // 419465580
101 }
102