├── .gitignore ├── README.md ├── block.go ├── block_test.go ├── generate-genesis.go ├── go.mod ├── go.sum └── transaction.go /.gitignore: -------------------------------------------------------------------------------- 1 | generate-genesis 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Genesis block generator 2 | ======================= 3 | 4 | Introduction 5 | ------------ 6 | 7 | This tool provides a convenient way to generate Genesis block for bitcoin-clone (altcoin) crypto currencies. 8 | 9 | 10 | Build 11 | ----- 12 | 13 | ```shell 14 | $ go mod init generate-genesis 15 | $ go mod tidy 16 | $ go build 17 | $ go test 18 | ``` 19 | 20 | Usage 21 | ----- 22 | 23 | ```shell 24 | $ ./generate-genesis -h 25 | Usage of ./generate-genesis: 26 | -algo string 27 | Algo to use: sha256, scrypt, x11, quark (default "sha256") 28 | -bits string 29 | Bits (default "1d00ffff") 30 | -coins uint 31 | Number of coins (default 5000000000) 32 | -maxprocs int 33 | Number of max CPUs that are simultaneously used 34 | -nonce uint 35 | Nonce value (default 2083236893) 36 | -profile string 37 | Write profile information into file (debug) 38 | -psz string 39 | pszTimestamp (default "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks") 40 | -pubkey string 41 | Pubkey (required) (default "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") 42 | -stepsize int 43 | Number of hashes computed per worker job (default 1024000) 44 | -timestamp uint 45 | Timestamp to use (default 1231006505) 46 | -verbose 47 | Show some messages 48 | -workers int 49 | Number of workers (goroutine) to use (if unset, use the CPU numbers) 50 | ``` 51 | 52 | Samples 53 | ------- 54 | 55 | ### Bitcoin (default) 56 | 57 | ```shell 58 | $ ./generate-genesis 59 | Ctrl Hash: 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f 60 | Target: 0x00000000ffff0000000000000000000000000000000000000000000000000000 61 | Blk Hash: 0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f 62 | Mkl Hash: 0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b 63 | Nonce: 2083236893 64 | Timestamp: 1231006505 65 | Pubkey: 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f 66 | Coins: 5000000000 67 | Psz: 'The Times 03/Jan/2009 Chancellor on brink of second bailout for banks' 68 | ``` 69 | 70 | ### Litecoin 71 | 72 | ```shell 73 | $ ./generate-genesis -algo scrypt -bits 1e0ffff0 -coins 5000000000 -nonce 2084524480 -timestamp 1317972665 -pubkey 040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9 -psz "NY Times 05/Oct/2011 Steve Jobs, Apple’s Visionary, Dies at 56" 74 | Ctrl Hash: 0x0000050c34a64b415b6b15b37f2216634b5b1669cb9a2e38d76f7213b0671e00 75 | Target: 0x00000ffff0000000000000000000000000000000000000000000000000000000 76 | Blk Hash: 0x0a2efd19744ffdff263e7223faf3a212c6040acfdc03d6b09f3e1ed1dd6f8272 77 | Mkl Hash: 0x97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9 78 | Nonce: 2084524493 79 | Timestamp: 1317972665 80 | Pubkey: 040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9 81 | Coins: 5000000000 82 | Psz: 'NY Times 05/Oct/2011 Steve Jobs, Apple’s Visionary, Dies at 56' 83 | ``` 84 | 85 | ### Dash (x11) 86 | 87 | ```shell 88 | $ ./generate-genesis -algo x11 -bits 1e0ffff0 -coins 5000000000 -psz "Wired 09/Jan/2014 The Grand Experiment Goes Live: Overstock.com Is Now Accepting Bitcoins" -pubkey "040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9" -timestamp 1390095618 -nonce 28917600 89 | Ctrl Hash: 0x00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6 90 | Target: 0x00000ffff0000000000000000000000000000000000000000000000000000000 91 | Blk Hash: 0x00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6 92 | Mkl Hash: 0xe0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7 93 | Nonce: 28917698 94 | Timestamp: 1390095618 95 | Pubkey: 040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9 96 | Coins: 5000000000 97 | Psz: 'Wired 09/Jan/2014 The Grand Experiment Goes Live: Overstock.com Is Now Accepting Bitcoins' 98 | ``` 99 | -------------------------------------------------------------------------------- /block.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | ) 7 | 8 | type Block struct { 9 | VersionNumber uint32 10 | PreviousHash []byte 11 | Hash []byte 12 | MerkleRoot []byte 13 | Timestamp uint32 14 | Bits uint32 15 | Nonce uint32 16 | TxCount int 17 | Txs []*Transaction 18 | Size int64 19 | } 20 | 21 | func (blk *Block) Serialize() []byte { 22 | var out bytes.Buffer 23 | 24 | uint32buffer := make([]byte, 4) 25 | 26 | binary.LittleEndian.PutUint32(uint32buffer, blk.VersionNumber) 27 | out.Write(uint32buffer) 28 | 29 | out.Write(blk.PreviousHash) 30 | out.Write(blk.MerkleRoot) 31 | 32 | binary.LittleEndian.PutUint32(uint32buffer, blk.Timestamp) 33 | out.Write(uint32buffer) 34 | 35 | binary.LittleEndian.PutUint32(uint32buffer, blk.Bits) 36 | out.Write(uint32buffer) 37 | 38 | binary.LittleEndian.PutUint32(uint32buffer, blk.Nonce) 39 | out.Write(uint32buffer) 40 | 41 | return out.Bytes() 42 | } 43 | 44 | func CreateBlock(params *GenesisParams, tx *Transaction) *Block { 45 | blk := new(Block) 46 | 47 | blk.MerkleRoot = tx.Hash 48 | 49 | blk.VersionNumber = 1 50 | blk.PreviousHash = make([]byte, 32) 51 | blk.MerkleRoot = tx.Hash 52 | 53 | blk.Timestamp = params.Timestamp 54 | blk.Nonce = params.Nonce 55 | blk.Bits = params.Bits 56 | 57 | blk.Txs = append(blk.Txs, tx) 58 | 59 | return blk 60 | } 61 | 62 | func (blk *Block) ComputeHash() { 63 | blk.Hash = ComputeSha256(ComputeSha256(blk.Serialize())) 64 | } 65 | 66 | // https://en.bitcoin.it/wiki/Block_hashing_algorithm 67 | func ComputeBlockHash(blk *Block) []byte { 68 | return ComputeSha256(ComputeSha256(blk.Serialize())) 69 | } 70 | -------------------------------------------------------------------------------- /block_test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/hex" 6 | "math/big" 7 | "testing" 8 | ) 9 | 10 | type GenesisTest struct { 11 | Name string 12 | Params GenesisParams 13 | MerkleRoot string 14 | BlockHash string 15 | IgnoreTarget bool 16 | } 17 | 18 | func CheckHash(t *testing.T, testName, expected string, current []byte) { 19 | decoded_len := hex.DecodedLen(len(expected)) 20 | decoded := make([]byte, decoded_len) 21 | _, err := hex.Decode(decoded, []byte(expected)) 22 | if err != nil { 23 | panic(err) 24 | } 25 | 26 | decoded = Reverse(decoded) 27 | 28 | if !bytes.Equal(decoded, current) { 29 | t.Errorf("Invalid hash for test %s: expected(0x%x)\n\t\t differs current(0x%x)", testName, decoded, current) 30 | } 31 | } 32 | 33 | func TestGeneration(t *testing.T) { 34 | tests := []GenesisTest{ 35 | { // this is official bitcoin 36 | Name: "bitcoin", 37 | Params: GenesisParams{ 38 | Algo: "sha256", 39 | Psz: "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks", 40 | Coins: 50 * 100000000, 41 | Pubkey: "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f", 42 | Timestamp: 1231006505, 43 | Nonce: 2083236893, 44 | Bits: 0x1d00ffff, 45 | }, 46 | MerkleRoot: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", 47 | BlockHash: "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f", 48 | }, 49 | { // this is official litecoin 50 | Name: "litecoin", 51 | Params: GenesisParams{ 52 | Algo: "scrypt", 53 | Psz: "NY Times 05/Oct/2011 Steve Jobs, Apple’s Visionary, Dies at 56", 54 | Coins: 50 * 100000000, 55 | Pubkey: "040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9", 56 | Timestamp: 1317972665, 57 | Nonce: 2084524493, 58 | Bits: 0x1e0ffff0, 59 | }, 60 | MerkleRoot: "97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9", 61 | BlockHash: "12a765e31ffd4059bada1e25190f6e98c99d9714d334efa41a195a7e7e04bfe2", 62 | }, 63 | { // this is bitcoin testnet 64 | Name: "bitcoin-testnet", 65 | Params: GenesisParams{ 66 | Algo: "sha256", 67 | Psz: "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks", 68 | Coins: 50 * 100000000, 69 | Pubkey: "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f", 70 | Timestamp: 1296688602, 71 | Nonce: 414098458, 72 | Bits: 0x1d00ffff, 73 | }, 74 | MerkleRoot: "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b", 75 | BlockHash: "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943", 76 | }, 77 | { // dash 78 | Name: "dash", 79 | Params: GenesisParams{ 80 | Algo: "x11", 81 | Psz: "Wired 09/Jan/2014 The Grand Experiment Goes Live: Overstock.com Is Now Accepting Bitcoins", 82 | Coins: 50 * 100000000, 83 | Pubkey: "040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9", 84 | Timestamp: 1390095618, 85 | Nonce: 28917698, 86 | Bits: 0x1e0ffff0, 87 | }, 88 | MerkleRoot: "e0028eb9648db56b1ac77cf090b99048a8007e2bb64b68f092c03c7f56a662c7", 89 | BlockHash: "00000ffd590b1485b3caadc19b22e6379c733355108f107a430458cdf3407ab6", 90 | }, 91 | { // pivx 92 | Name: "pivx", 93 | Params: GenesisParams{ 94 | Algo: "quark", 95 | Psz: "U.S. News & World Report Jan 28 2016 With His Absence, Trump Dominates Another Debate", 96 | Coins: 250 * 100000000, 97 | Pubkey: "04c10e83b2703ccf322f7dbd62dd5855ac7c10bd055814ce121ba32607d573b8810c02c0582aed05b4deb9c4b77b26d92428c61256cd42774babea0a073b2ed0c9", 98 | Timestamp: 1454124731, 99 | Nonce: 8451331, 100 | Bits: 0x1e0ffff0, 101 | }, 102 | MerkleRoot: "1b2ef6e2f28be914103a277377ae7729dcd125dfeb8bf97bd5964ba72b6dc39b", 103 | BlockHash: "00000b347ed09c174de45bc2f34bcd4a12f7f09d63d2e49c924cab7d2014dddb", 104 | }, 105 | { // dogecoin 106 | Name: "dogecoin", 107 | Params: GenesisParams{ 108 | Algo: "sha256", 109 | Psz: "Nintondo", 110 | Coins: 88 * 100000000, 111 | Pubkey: "040184710fa689ad5023690c80f3a49c8f13f8d45b8c857fbcbc8bc4a8e4d3eb4b10f4d4604fa08dce601aaf0f470216fe1b51850b4acf21b179c45070ac7b03a9", 112 | Timestamp: 1386325540, 113 | Nonce: 99943, 114 | Bits: 0x1e0ffff0, 115 | }, 116 | MerkleRoot: "5b2a3f53f605d62c53e62932dac6925e3d74afa5a4b459745c36d42d0ed26a69", 117 | BlockHash: "1a91e3dace36e2be3bf030a65679fe821aa1d6ef92e7c9902eb318182c355691", 118 | IgnoreTarget: true, 119 | }, 120 | } 121 | 122 | for _, test := range tests { 123 | var current big.Int 124 | 125 | tx := CreateTransaction( 126 | test.Params.Psz, 127 | test.Params.Coins, 128 | test.Params.Pubkey, 129 | ) 130 | tx.ComputeHash() 131 | 132 | blk := CreateBlock(&test.Params, tx) 133 | 134 | switch test.Params.Algo { 135 | case "sha256": 136 | blk.ComputeHash() 137 | case "scrypt": 138 | blk.ComputeHash() 139 | case "x11": 140 | blk.Hash = ComputeX11(blk.Serialize()) 141 | case "quark": 142 | blk.Hash = ComputeQuark(blk.Serialize()) 143 | } 144 | 145 | CheckHash(t, test.Name, test.BlockHash, blk.Hash) 146 | CheckHash(t, test.Name, test.MerkleRoot, blk.MerkleRoot) 147 | 148 | // Check difficulty as well 149 | target := ComputeTarget(test.Params.Bits) 150 | 151 | // In case of scrypt (litecoin), the check is done against scrypt, but sha256 is the block hash. 152 | // Therefore, we need to overwrite the blockhash for the target test. 153 | if test.Params.Algo == "scrypt" { 154 | blk.Hash = ComputeScrypt(blk.Serialize()) 155 | } 156 | 157 | if test.IgnoreTarget { 158 | // fmt.Printf("Target test ignored for test %s.\n", test.Name) 159 | continue 160 | } 161 | 162 | current.SetBytes(Reverse(blk.Hash)) 163 | if 1 != target.Cmp(¤t) { 164 | t.Error("Target not reached.") 165 | return 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /generate-genesis.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/sha256" 5 | "encoding/binary" 6 | "flag" 7 | "fmt" 8 | "math/big" 9 | "os" 10 | "runtime" 11 | "runtime/pprof" 12 | "strconv" 13 | 14 | quark "github.com/mycroft/goquarkhash" 15 | x11 "gitlab.com/nitya-sattva/go-x11" 16 | "golang.org/x/crypto/scrypt" 17 | ) 18 | 19 | var ( 20 | algo string 21 | psz string 22 | coins uint64 23 | pubkey string 24 | timestamp, nonce uint 25 | bits string 26 | profile string 27 | maxprocs, workers int 28 | stepsize int 29 | verbose bool 30 | ) 31 | 32 | func init() { 33 | flag.StringVar(&algo, "algo", "sha256", "Algo to use: sha256, scrypt, x11, quark") 34 | flag.StringVar(&psz, "psz", "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks", "pszTimestamp") 35 | flag.Uint64Var(&coins, "coins", uint64(50*100000000), "Number of coins") 36 | flag.StringVar(&pubkey, "pubkey", "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f", "Pubkey (required)") 37 | flag.UintVar(×tamp, "timestamp", 1231006505, "Timestamp to use") 38 | flag.UintVar(&nonce, "nonce", 2083236893, "Nonce value") 39 | flag.StringVar(&bits, "bits", "1d00ffff", "Bits") 40 | flag.StringVar(&profile, "profile", "", "Write profile information into file (debug)") 41 | flag.IntVar(&workers, "workers", 0, "Number of workers (goroutine) to use (if unset, use the CPU numbers)") 42 | flag.IntVar(&maxprocs, "maxprocs", 0, "Number of max CPUs that are simultaneously used") 43 | flag.IntVar(&stepsize, "stepsize", 1024*1000, "Number of hashes computed per worker job") 44 | flag.BoolVar(&verbose, "verbose", false, "Show some messages") 45 | } 46 | 47 | func ComputeSha256(content []byte) []byte { 48 | m := sha256.New() 49 | m.Write(content) 50 | 51 | return m.Sum(nil) 52 | } 53 | 54 | func ComputeScrypt(content []byte) []byte { 55 | scryptHash, err := scrypt.Key(content, content, 1024, 1, 1, 32) 56 | 57 | if err != nil { 58 | panic(err) 59 | } 60 | 61 | return scryptHash 62 | } 63 | 64 | func ComputeX11(content []byte) []byte { 65 | out := make([]byte, 32) 66 | 67 | hasher := x11.New() 68 | hasher.Hash(content, out) 69 | 70 | return out 71 | } 72 | 73 | func ComputeQuark(content []byte) []byte { 74 | return quark.QuarkHash(content) 75 | } 76 | 77 | func Reverse(in []byte) []byte { 78 | out := make([]byte, len(in)) 79 | 80 | for i := 0; i < len(in); i++ { 81 | out[i] = in[len(in)-i-1] 82 | } 83 | 84 | return out 85 | } 86 | 87 | type GenesisParams struct { 88 | Algo string 89 | Psz string 90 | Coins uint64 91 | Pubkey string 92 | Timestamp uint32 93 | Nonce uint32 94 | Bits uint32 95 | } 96 | 97 | func ComputeTarget(bits uint32) big.Int { 98 | var target big.Int 99 | 100 | target_bytes := make([]byte, bits>>24) 101 | binary.BigEndian.PutUint32(target_bytes, uint32(bits%(1<<24)<<8)) 102 | 103 | target.SetBytes(target_bytes) 104 | 105 | return target 106 | } 107 | 108 | type Job struct { 109 | StartingNonce uint32 110 | MaxNonce uint32 111 | Timestamp uint32 112 | } 113 | 114 | func main() { 115 | flag.Parse() 116 | 117 | if profile != "" { 118 | f, err := os.Create(profile) 119 | if err != nil { 120 | panic(err) 121 | } 122 | pprof.StartCPUProfile(f) 123 | defer pprof.StopCPUProfile() 124 | } 125 | 126 | if 0 != maxprocs { 127 | runtime.GOMAXPROCS(maxprocs) 128 | } 129 | 130 | if psz == "" { 131 | fmt.Printf("Require a psz. Please set -psz") 132 | os.Exit(1) 133 | } 134 | 135 | jobs_num := runtime.NumCPU() 136 | if workers != 0 { 137 | jobs_num = workers 138 | } 139 | 140 | jobs := make(chan Job, jobs_num) 141 | results := make(chan bool, jobs_num) 142 | 143 | for i := 0; i < jobs_num; i++ { 144 | go SearchWorker(i, jobs, results) 145 | } 146 | 147 | nonce_current := uint32(nonce) 148 | nonce_iterator := uint32(stepsize) 149 | 150 | for { 151 | var res bool 152 | if jobs_num > 0 { 153 | next_max_nonce := nonce_current + nonce_iterator 154 | jobs <- Job{ 155 | StartingNonce: nonce_current, 156 | MaxNonce: next_max_nonce, 157 | Timestamp: uint32(timestamp), 158 | } 159 | if next_max_nonce < nonce_current { 160 | timestamp++ 161 | fmt.Println("nonce was reset. Timestamp is now", timestamp) 162 | } 163 | nonce_current = next_max_nonce 164 | 165 | jobs_num-- 166 | } else if jobs_num == 0 { 167 | // Wait for a job to be completed 168 | res = <-results 169 | jobs_num++ 170 | } 171 | 172 | if res { 173 | break 174 | } 175 | } 176 | } 177 | 178 | func SearchWorker(instance int, jobs <-chan Job, results chan<- bool) { 179 | var current big.Int 180 | var found bool 181 | 182 | bits_uint32, err := strconv.ParseUint(bits, 16, 32) 183 | if err != nil { 184 | panic(err) 185 | } 186 | 187 | target := ComputeTarget(uint32(bits_uint32)) 188 | 189 | for job := range jobs { 190 | if verbose { 191 | fmt.Printf( 192 | "Worker %2d: Nonce: %10d to Nonce: %10d timestamp: %10d\n", 193 | instance, 194 | job.StartingNonce, 195 | job.MaxNonce, 196 | job.Timestamp, 197 | ) 198 | } 199 | params := new(GenesisParams) 200 | params.Algo = algo 201 | params.Psz = psz 202 | params.Coins = coins 203 | params.Pubkey = pubkey 204 | params.Timestamp = job.Timestamp 205 | params.Nonce = job.StartingNonce 206 | params.Bits = uint32(bits_uint32) 207 | 208 | tx := CreateTransaction( 209 | params.Psz, 210 | params.Coins, 211 | params.Pubkey, 212 | ) 213 | tx.ComputeHash() 214 | 215 | blk := CreateBlock(params, tx) 216 | 217 | for { 218 | switch params.Algo { 219 | case "sha256": 220 | blk.ComputeHash() 221 | case "scrypt": 222 | blk.Hash = ComputeScrypt(blk.Serialize()) 223 | case "x11": 224 | blk.Hash = ComputeX11(blk.Serialize()) 225 | case "quark": 226 | blk.Hash = quark.QuarkHash(blk.Serialize()) 227 | } 228 | 229 | current.SetBytes(Reverse(blk.Hash)) 230 | if 1 == target.Cmp(¤t) { 231 | found = true 232 | PrintFound(blk, blk.Hash, target) 233 | break 234 | } 235 | 236 | blk.Nonce++ 237 | if blk.Nonce == job.MaxNonce { 238 | break 239 | } 240 | } 241 | 242 | if found == true { 243 | results <- true 244 | break 245 | } 246 | 247 | results <- false 248 | } 249 | 250 | } 251 | 252 | func PrintFound(blk *Block, hash []byte, target big.Int) { 253 | fmt.Printf("Ctrl Hash:\t0x%x\n", Reverse(hash)) 254 | target_hash := make([]byte, 32) 255 | copy(target_hash[32-len(target.Bytes()):], target.Bytes()) 256 | fmt.Printf("Target:\t\t0x%x\n", target_hash) 257 | fmt.Printf("Blk Hash:\t0x%x\n", Reverse(blk.Hash)) 258 | fmt.Printf("Mkl Hash:\t0x%x\n", Reverse(blk.MerkleRoot)) 259 | fmt.Printf("Nonce:\t\t%d\n", blk.Nonce) 260 | fmt.Printf("Timestamp:\t%d\n", blk.Timestamp) 261 | fmt.Printf("Pubkey:\t\t%s\n", pubkey) 262 | fmt.Printf("Coins:\t\t%d\n", coins) 263 | fmt.Printf("Psz:\t\t'%s'\n", psz) 264 | } 265 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module generate-genesis 2 | 3 | go 1.22.2 4 | 5 | require ( 6 | github.com/mycroft/goquarkhash v0.0.0-20180708083435-35950a5747a3 7 | gitlab.com/nitya-sattva/go-x11 v0.0.0-20161218191547-fe7663eb78fd 8 | golang.org/x/crypto v0.22.0 9 | ) 10 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/mycroft/goquarkhash v0.0.0-20180708083435-35950a5747a3 h1:sHiaxaeHRhCFEc2oTjOKhthWlAV6dgNod35/aqSMsMs= 2 | github.com/mycroft/goquarkhash v0.0.0-20180708083435-35950a5747a3/go.mod h1:iVmOdSa1f4XitqCZmi6Rzr1E14OQsn1vRNXIWekwgAE= 3 | gitlab.com/nitya-sattva/go-x11 v0.0.0-20161218191547-fe7663eb78fd h1:vo96ljS9/ZiG8SWCmgEbAzU/Eol4xM6MEEEbTRS7V/Q= 4 | gitlab.com/nitya-sattva/go-x11 v0.0.0-20161218191547-fe7663eb78fd/go.mod h1:0Hgc0AzU3aAodvipSCrgE6Y+HYIjdz/VdShJQhmPC94= 5 | golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= 6 | golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= 7 | -------------------------------------------------------------------------------- /transaction.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/binary" 6 | "encoding/hex" 7 | "fmt" 8 | ) 9 | 10 | type Transaction struct { 11 | Size uint32 12 | Hash []byte 13 | VersionNumber uint32 14 | InputCount int 15 | Input []TransactionInput 16 | OutputCount int 17 | Output []TransactionOutput 18 | LockTime uint32 19 | } 20 | 21 | type TransactionInput struct { 22 | TxHash []byte 23 | TxIndex uint32 24 | ScriptLength int 25 | Script []byte 26 | SequenceNumber uint32 27 | } 28 | 29 | type TransactionOutput struct { 30 | Value uint64 31 | ScriptLength int 32 | Script []byte 33 | } 34 | 35 | func CreateInputScript(psz string) []byte { 36 | // Signature script (coinbase) 37 | prefix := []byte{0x04, 0xff, 0xff, 0x00, 0x1d, 0x01, 0x04} 38 | 39 | if len(psz) >= 0x4c && len(psz) <= 0xff { 40 | prefix = append(prefix, byte(0x4c)) // OP_PUSHDATA1 41 | } else if len(psz) > 0xff { 42 | panic("Script length is too long") 43 | } 44 | 45 | prefix = append(prefix, byte(len(psz))) 46 | prefix = append(prefix, []byte(psz)...) 47 | 48 | return prefix 49 | } 50 | 51 | func CreateOutputScript(pubkey_hex string) []byte { 52 | var script bytes.Buffer 53 | 54 | decoded_len := hex.DecodedLen(len(pubkey_hex)) 55 | pubkey_decoded := make([]byte, decoded_len) 56 | 57 | n, err := hex.Decode(pubkey_decoded, []byte(pubkey_hex)) 58 | if err != nil { 59 | panic(err) 60 | } 61 | 62 | if n != 65 && n != 33 { 63 | fmt.Printf("Warning: Pubkey is not 33 or 65 char long. Are you sure it is a valid ecdsa key?\n") 64 | } 65 | 66 | script.WriteByte(byte(n)) 67 | script.Write(pubkey_decoded) 68 | script.WriteByte(0xac) // OP_CHECKSIG 69 | 70 | return script.Bytes() 71 | } 72 | 73 | func CreateTransaction(psz string, coins uint64, pubkey_hex string) *Transaction { 74 | tx := new(Transaction) 75 | 76 | tx.VersionNumber = 1 77 | 78 | inputScript := CreateInputScript(psz) 79 | 80 | tx.InputCount = 1 81 | tx.Input = append(tx.Input, TransactionInput{ 82 | TxHash: make([]byte, 32), 83 | TxIndex: uint32(0xffffffff), 84 | ScriptLength: len(inputScript), 85 | Script: inputScript, 86 | SequenceNumber: 0xffffffff, 87 | }) 88 | 89 | outputScript := CreateOutputScript(pubkey_hex) 90 | 91 | tx.OutputCount = 1 92 | tx.Output = append(tx.Output, TransactionOutput{ 93 | Value: coins, 94 | Script: outputScript, 95 | ScriptLength: len(outputScript), 96 | }) 97 | 98 | return tx 99 | } 100 | 101 | func (tx *Transaction) ComputeHash() []byte { 102 | tx.Hash = ComputeSha256(ComputeSha256(tx.Serialize())) 103 | return tx.Hash 104 | } 105 | 106 | func (tx_input *TransactionInput) Serialize() []byte { 107 | var out bytes.Buffer 108 | 109 | uint32buff := make([]byte, 4) 110 | 111 | out.Write(tx_input.TxHash) 112 | 113 | binary.LittleEndian.PutUint32(uint32buff, tx_input.TxIndex) 114 | out.Write(uint32buff) 115 | out.WriteByte(byte(tx_input.ScriptLength)) 116 | out.Write(tx_input.Script) 117 | 118 | binary.LittleEndian.PutUint32(uint32buff, tx_input.SequenceNumber) 119 | out.Write(uint32buff) 120 | 121 | return out.Bytes() 122 | } 123 | 124 | func (tx_output *TransactionOutput) Serialize() []byte { 125 | var out bytes.Buffer 126 | uint64buff := make([]byte, 8) 127 | 128 | binary.LittleEndian.PutUint64(uint64buff, tx_output.Value) 129 | out.Write(uint64buff) 130 | out.WriteByte(byte(tx_output.ScriptLength)) 131 | out.Write(tx_output.Script) 132 | 133 | return out.Bytes() 134 | } 135 | 136 | func (tx *Transaction) Serialize() []byte { 137 | var out bytes.Buffer 138 | 139 | uint32buff := make([]byte, 4) 140 | binary.LittleEndian.PutUint32(uint32buff, tx.VersionNumber) 141 | 142 | out.Write(uint32buff) // Version 143 | out.WriteByte(byte(tx.InputCount)) // Input count (1) 144 | out.Write(tx.Input[0].Serialize()) // Input 145 | 146 | out.WriteByte(byte(tx.OutputCount)) // Output count 147 | out.Write(tx.Output[0].Serialize()) // Input 148 | 149 | binary.LittleEndian.PutUint32(uint32buff, tx.LockTime) 150 | out.Write(uint32buff) // Locktime 151 | 152 | return out.Bytes() 153 | } 154 | --------------------------------------------------------------------------------