func TestTransactionSignInputs(t *testing.T) { tx := &Transaction{} // Panics if txns already signed tx.Sigs = append(tx.Sigs, cipher.Sig{}) assert.Panics(t, func() { tx.SignInputs([]cipher.SecKey{}) }) // Panics if not enough keys tx = &Transaction{} ux, s := makeUxOutWithSecret(t) tx.PushInput(ux.Hash()) ux2, s2 := makeUxOutWithSecret(t) tx.PushInput(ux2.Hash()) tx.PushOutput(makeAddress(), 40, 80) assert.Equal(t, len(tx.Sigs), 0) assert.Panics(t, func() { tx.SignInputs([]cipher.SecKey{s}) }) assert.Equal(t, len(tx.Sigs), 0) // Valid signing h := tx.HashInner() assert.NotPanics(t, func() { tx.SignInputs([]cipher.SecKey{s, s2}) }) assert.Equal(t, len(tx.Sigs), 2) assert.Equal(t, tx.HashInner(), h) p := cipher.PubKeyFromSecKey(s) a := cipher.AddressFromPubKey(p) p = cipher.PubKeyFromSecKey(s2) a2 := cipher.AddressFromPubKey(p) assert.Nil(t, cipher.ChkSig(a, cipher.AddSHA256(h, tx.In[0]), tx.Sigs[0])) assert.Nil(t, cipher.ChkSig(a2, cipher.AddSHA256(h, tx.In[1]), tx.Sigs[1])) assert.NotNil(t, cipher.ChkSig(a, h, tx.Sigs[1])) assert.NotNil(t, cipher.ChkSig(a2, h, tx.Sigs[0])) }
// addBlockToBlockchain test helper function // Adds 2 blocks to the blockchain and return an unspent that has >0 coin hours func addBlockToBlockchain(t *testing.T, bc *Blockchain) (coin.Block, coin.UxOut) { // Split the genesis block into two transactions assert.Equal(t, len(bc.GetUnspent().Array()), 1) ux := bc.GetUnspent().Array()[0] assert.Equal(t, ux.Body.Address, genAddress) pub := cipher.PubKeyFromSecKey(genSecret) assert.Equal(t, genAddress, cipher.AddressFromPubKey(pub)) sig := cipher.SignHash(ux.Hash(), genSecret) assert.Nil(t, cipher.ChkSig(ux.Body.Address, ux.Hash(), sig)) tx, sec := makeTransactionForChainWithHoursFee(t, bc, ux, genSecret, 0, 0) b, err := bc.NewBlockFromTransactions(coin.Transactions{tx}, _incTime) assert.Nil(t, err) assertExecuteBlock(t, bc, b, tx) assert.Equal(t, len(bc.GetUnspent().Array()), 2) // Spend one of them // The other will have hours now ux = coin.UxOut{} for _, u := range bc.GetUnspent().Pool { if u.Body.Address != genAddress { ux = u break } } assert.NotEqual(t, ux.Body.Address, cipher.Address{}) assert.NotEqual(t, ux.Body.Address, genAddress) pub = cipher.PubKeyFromSecKey(sec) addr := cipher.AddressFromPubKey(pub) assert.Equal(t, ux.Body.Address, addr) tx, _ = makeTransactionForChainWithHoursFee(t, bc, ux, sec, 0, 0) b, err = bc.NewBlockFromTransactions(coin.Transactions{tx}, bc.Time()+_incTime) assert.Nil(t, err) assertExecuteBlock(t, bc, b, tx) assert.Equal(t, len(bc.GetUnspent().Array()), 2) // Check that the output in the 2nd block is owned by genesis, // and has coin hours for _, u := range bc.GetUnspent().Pool { if u.Body.Address == genAddress { ux = u break } } assert.Equal(t, ux.Body.Address, genAddress) assert.Equal(t, ux.Head.BkSeq, uint64(1)) assert.True(t, ux.CoinHours(bc.Time()) > 0) return b, ux }
func makeTransactionForChainWithHoursFee(t *testing.T, bc *Blockchain, ux coin.UxOut, sec cipher.SecKey, hours, fee uint64) (coin.Transaction, cipher.SecKey) { chrs := ux.CoinHours(bc.Time()) if chrs < hours+fee { log.Panicf("CoinHours underflow. Have %d, need at least %d", chrs, hours+fee) } assert.Equal(t, cipher.AddressFromPubKey(cipher.PubKeyFromSecKey(sec)), ux.Body.Address) knownUx, exists := bc.GetUnspent().Get(ux.Hash()) assert.True(t, exists) assert.Equal(t, knownUx, ux) tx := coin.Transaction{} tx.PushInput(ux.Hash()) p, newSec := cipher.GenerateKeyPair() addr := cipher.AddressFromPubKey(p) tx.PushOutput(addr, 1e6, hours) coinsOut := ux.Body.Coins - 1e6 if coinsOut > 0 { tx.PushOutput(genAddress, coinsOut, chrs-hours-fee) } tx.SignInputs([]cipher.SecKey{sec}) assert.Equal(t, len(tx.Sigs), 1) assert.Nil(t, cipher.ChkSig(ux.Body.Address, cipher.AddSHA256(tx.HashInner(), tx.In[0]), tx.Sigs[0])) tx.UpdateHeader() assert.Nil(t, tx.Verify()) err := bc.VerifyTransaction(tx) assert.Nil(t, err) return tx, newSec }
func (wlt *Wallet) GenerateAddresses(num int) []cipher.Address { var seckeys []cipher.SecKey var sd []byte var err error if len(wlt.Entries) == 0 { sd, seckeys = cipher.GenerateDeterministicKeyPairsSeed([]byte(wlt.getLastSeed()), num) } else { sd, err = hex.DecodeString(wlt.getLastSeed()) if err != nil { log.Panicf("decode hex seed failed,%v", err) } sd, seckeys = cipher.GenerateDeterministicKeyPairsSeed(sd, num) } wlt.setLastSeed(hex.EncodeToString(sd)) addrs := make([]cipher.Address, len(seckeys)) for i, s := range seckeys { p := cipher.PubKeyFromSecKey(s) a := cipher.AddressFromPubKey(p) addrs[i] = a wlt.Entries = append(wlt.Entries, WalletEntry{ Address: a, Secret: s, Public: p, }) } return addrs }
//test signatures func TestCrypto2(t *testing.T) { a := "5a42c0643bdb465d90bf673b99c14f5fa02db71513249d904573d2b8b63d353d" b, err := hex.DecodeString(a) if err != nil { t.Fatal(err) } if len(b) != 32 { t.Fatal() } seckey := cipher.NewSecKey(b) pubkey := cipher.PubKeyFromSecKey(seckey) addr := cipher.AddressFromPubKey(pubkey) _ = addr test := []byte("test message") hash := cipher.SumSHA256(test) err = cipher.TestSecKeyHash(seckey, hash) if err != nil { t.Fatal() } }
func WalletEntryFromReadable(w *ReadableWalletEntry) WalletEntry { // SimpleWallet entries are shared as a form of identification, the secret key // is not required // TODO -- fix lib/base58 to not panic on invalid input -- should // return error, so we can detect a broken wallet. if w.Address == "" { //log.Panic("ReadableWalletEntry has no Address") } var s cipher.SecKey if w.Secret != "" { s = cipher.MustSecKeyFromHex(w.Secret) } //regen from the private key //redundant/ if w.Address == "" { addr := cipher.AddressFromSecKey(s) pub := cipher.PubKeyFromSecKey(s) return WalletEntry{ Address: addr, Public: pub, Secret: s, } } return WalletEntry{ Address: cipher.MustDecodeBase58Address(w.Address), Public: cipher.MustPubKeyFromHex(w.Public), Secret: s, } }
//sign a block with seckey func (bc *BlockChain) SignBlock(seckey cipher.SecKey, block *Block) { //set signature if PubKeyHash(cipher.PubKeyFromSecKey(seckey)) != bc.Genesis().Head.PrevHash { log.Panic("NewBlock, invalid sec key") } block.Sig = cipher.SignHash(block.Head.Hash(), seckey) }
func (self *Visor) CreateGenesisBlockInit() (SignedBlock, error) { self.GenesisPreconditions() if len(self.Blockchain.Blocks) != 0 || len(self.blockSigs.Sigs) != 0 { log.Panic("Blockchain already has genesis") } if self.Config.BlockchainPubkey != cipher.PubKeyFromSecKey(self.Config.BlockchainSeckey) { log.Panicf("Cannot create genesis block. Invalid secret key for pubkey") } gb := self.Blockchain.CreateGenesisBlock(self.Config.GenesisAddress, self.Config.GenesisTimestamp, self.Config.GenesisCoinVolume) sb := self.SignBlock(gb) if err := self.verifySignedBlock(&sb); err != nil { log.Panic("Signed a fresh genesis block, but its invalid: %v", err) } self.blockSigs.record(&sb) log.Printf("New Genesis:") log.Printf("genesis_time= %v", sb.Block.Head.Time) log.Printf("genesis_address= %v", self.Config.GenesisAddress.String()) log.Printf("genesis_signature= %v", sb.Sig.Hex()) return sb, nil }
// GenesisPreconditions panics if conditions for genesis block are not met func (vs *Visor) GenesisPreconditions() { //if seckey is set if vs.Config.BlockchainSeckey != (cipher.SecKey{}) { if vs.Config.BlockchainPubkey != cipher.PubKeyFromSecKey(vs.Config.BlockchainSeckey) { log.Panicf("Cannot create genesis block. Invalid secret key for pubkey") } } }
// GenerateAddresses generates bitcoin addresses. func GenerateAddresses(seed []byte, num int) (string, []coin.AddressEntry) { sd, seckeys := cipher.GenerateDeterministicKeyPairsSeed(seed, num) entries := make([]coin.AddressEntry, num) for i, sec := range seckeys { pub := cipher.PubKeyFromSecKey(sec) entries[i].Address = cipher.BitcoinAddressFromPubkey(pub) entries[i].Public = pub.Hex() if !HideSeckey { entries[i].Secret = cipher.BitcoinWalletImportFormatFromSeckey(sec) } } return fmt.Sprintf("%2x", sd), entries }
func NewBlockChain(seckey cipher.SecKey) *BlockChain { //genesis block var b Block b.Head.Time = 0 b.Head.BkSeq = 0 b.Head.PrevHash = PubKeyHash(cipher.PubKeyFromSecKey(seckey)) b.Head.BodyHash = cipher.SHA256{} //blockchain var bc BlockChain bc.Blocks = append(bc.Blocks, b) return &bc }
// Generating secret key, address, public key by given // GET/POST // bc - bool - is bitcoin type (optional) - default: true // n - int - Generation count (optional) - default: 1 // s - bool - is hide secret key (optional) - default: false // seed - string - seed hash func apiCreateAddressHandler(gateway *daemon.Gateway) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var seed string = r.FormValue("seed") var err error if seed == "" { wh.Error400(w, "Empty seed") return } isBitcoin, err = strconv.ParseBool(r.FormValue("bc")) if err != nil { isBitcoin = true } genCount, err := strconv.Atoi(r.FormValue("n")) if err != nil { genCount = 1 } hideSecKey, err = strconv.ParseBool(r.FormValue("s")) if err != nil { hideSecKey = false } wallet := Wallet{ Meta: make(map[string]string), //map[string]string Entries: make([]KeyEntry, genCount), } if isBitcoin == false { wallet.Meta = map[string]string{"coin": "skycoin"} } else { wallet.Meta = map[string]string{"coin": "bitcoin"} } wallet.Meta["seed"] = seed seckeys := cipher.GenerateDeterministicKeyPairs([]byte(seed), genCount) for i, sec := range seckeys { pub := cipher.PubKeyFromSecKey(sec) wallet.Entries[i] = getKeyEntry(pub, sec) } ret := wallet wh.SendOr404(w, ret) } }
//panics if conditions for genesis block are not met func (self *Visor) GenesisPreconditions() { //if len(self.Blockchain.Blocks) != 0 || len(self.blockSigs.Sigs) != 0 { // log.Panic("Blockchain already has genesis") //} //if seckey is set if self.Config.BlockchainSeckey != (cipher.SecKey{}) { if self.Config.BlockchainPubkey != cipher.PubKeyFromSecKey(self.Config.BlockchainSeckey) { log.Panicf("Cannot create genesis block. Invalid secret key for pubkey") } } }
// Creates a normal Visor given a master's public key func NewVisor(c VisorConfig) *Visor { logger.Debug("Creating new visor") // Make sure inputs are correct if c.IsMaster { logger.Debug("Visor is master") } if c.IsMaster { if c.BlockchainPubkey != cipher.PubKeyFromSecKey(c.BlockchainSeckey) { log.Panicf("Cannot run in master: invalid seckey for pubkey") } } // Load the blockchain the block signatures blockchain := loadBlockchain(c.BlockchainFile, c.GenesisAddress) blockSigs, err := LoadBlockSigs(c.BlockSigsFile) if err != nil { if os.IsNotExist(err) { logger.Info("BlockSigsFile \"%s\" not found", c.BlockSigsFile) } else { log.Panicf("Failed to load BlockSigsFile \"%s\"", c.BlockSigsFile) } blockSigs = NewBlockSigs() } v := &Visor{ Config: c, Blockchain: blockchain, blockSigs: blockSigs, Unconfirmed: NewUnconfirmedTxnPool(), //Wallets: wallets, } // Load the genesis block and sign it, if we need one if len(blockchain.Blocks) == 0 { if (c.BlockchainSeckey == cipher.SecKey{}) || (c.IsMaster == false) { v.CreateGenesisBlock() } else { v.CreateGenesisBlockInit() } } err = blockSigs.Verify(c.BlockchainPubkey, blockchain) if err != nil { log.Panicf("Invalid block signatures: %v", err) } return v }
func main() { initLogging(logging.DEBUG, true) cfg := initConfig() initProfiling(cfg.HttpProf) // print pubkey so that client can use that to communicate with server sk := cipher.MustSecKeyFromHex(cfg.Seckey) logger.Info("pubkey:%v", cipher.PubKeyFromSecKey(sk).Hex()) s := server.New(cfg) // Bind supported coins s.BindCoins( &bitcoin.Bitcoin{}, skycoin.New(cfg.NodeAddresses[skycoin.Type]), mzcoin.New(cfg.NodeAddresses[mzcoin.Type])) s.Run() }
func encrypt(r interface{}, pubkey string, seckey string) (*pp.EncryptReq, error) { encData, nonce, err := pp.Encrypt(r, pubkey, seckey) if err != nil { return nil, err } s, err := cipher.SecKeyFromHex(seckey) if err != nil { return nil, err } p := cipher.PubKeyFromSecKey(s) return &pp.EncryptReq{ Pubkey: pp.PtrString(p.Hex()), Nonce: nonce, Encryptdata: encData, }, nil }
func TestAddress2(t *testing.T) { a := "5a42c0643bdb465d90bf673b99c14f5fa02db71513249d904573d2b8b63d353d" b, err := hex.DecodeString(a) if err != nil { t.Fail() } if len(b) != 32 { t.Fail() } seckey := cipher.NewSecKey(b) pubkey := cipher.PubKeyFromSecKey(seckey) addr := cipher.AddressFromPubKey(pubkey) _ = addr ///func SignHash(hash cipher.SHA256, sec SecKey) (Sig, error) { }
func main() { registerFlags() parseFlags() w := Wallet{ Meta: make(map[string]string), //map[string]string Entries: make([]KeyEntry, genCount), } if BitcoinAddress == false { w.Meta = map[string]string{"coin": "skycoin"} } else { w.Meta = map[string]string{"coin": "bitcoin"} } if seed == "" { //generate a new seed, as hex string seed = cipher.SumSHA256(cipher.RandByte(1024)).Hex() } w.Meta["seed"] = seed seckeys := cipher.GenerateDeterministicKeyPairs([]byte(seed), genCount) for i, sec := range seckeys { pub := cipher.PubKeyFromSecKey(sec) w.Entries[i] = getKeyEntry(pub, sec) } output, err := json.MarshalIndent(w, "", " ") if err != nil { fmt.Printf("Error formating wallet to JSON. Error : %s\n", err.Error()) return } fmt.Printf("%s\n", string(output)) }
// Checks that the public key is derivable from the secret key, // and that the public key is associated with the address func (self *WalletEntry) Verify() error { if cipher.PubKeyFromSecKey(self.Secret) != self.Public { return errors.New("Invalid public key for secret key") } return self.VerifyPublic() }
//////////////////////////////////////////////////////////////////////////////// // // main // //////////////////////////////////////////////////////////////////////////////// func main() { cmd_line_args_process() // PERFORMANCE: cipher.DebugLevel1 = false cipher.DebugLevel2 = false var X []*MinimalConnectionManager var hack_global_seqno uint64 = 0 seed := "hdhdhdkjashfy7273" _, SecKeyArray := cipher.GenerateDeterministicKeyPairsSeed([]byte(seed), Cfg_simu_num_node) for i := 0; i < Cfg_simu_num_node; i++ { cm := MinimalConnectionManager{} // Reason for mutual registration: (1) when conn man receives // messages, it needs to notify the node; (2) when node has // processed a mesage, it might need to use conn man to send // some data out. nodePtr := consensus.NewConsensusParticipantPtr(&cm) s := SecKeyArray[i] nodePtr.SetPubkeySeckey(cipher.PubKeyFromSecKey(s), s) cm.theNodePtr = nodePtr X = append(X, &cm) } if false { fmt.Printf("Got %d nodes\n", len(X)) } if Cfg_simu_topology_is_random { fmt.Printf("CONFIG Topology: connecting %d nodes randomly with approx"+ " %d nearest-neighbors in and approx %d nearest-neighbors out.\n", Cfg_simu_num_node, Cfg_simu_fanout_per_node, Cfg_simu_fanout_per_node) for i, _ := range X { cm := X[i] for g := 0; g < Cfg_simu_fanout_per_node; g++ { j := mathrand.Intn(Cfg_simu_num_node) if i != j { cm.RegisterPublisher(X[j]) } } } } else { fmt.Printf("CONFIG Topology: connecting %d nodes via one (thick)"+ " circle with approx %d nearest-neighbors in and approx %d "+ "nearest-neighbors out.\n", Cfg_simu_num_node, Cfg_simu_fanout_per_node, Cfg_simu_fanout_per_node) n := len(X) for i := 0; i < n; i++ { cm := X[i] c_left := int(Cfg_simu_fanout_per_node / 2) c_right := Cfg_simu_fanout_per_node - c_left for c := 0; c < c_left; c++ { j := (i - 1 - c + n) % n cm.RegisterPublisher(X[j]) } for c := 0; c < c_right; c++ { j := (i + 1 + c) % n cm.RegisterPublisher(X[j]) } } } // Connect. PROD: This should request connections. The // connections can be accepted, rejected or never answered. Such // replies are asynchronous. SIMU: we connect synchronously. for i, _ := range X { X[i].RequestConnectionToAllMyPublisher() } global_seqno2h := make(map[uint64]cipher.SHA256) global_seqno2h_alt := make(map[uint64]cipher.SHA256) iter := 0 block_round := 0 done_processing_messages := false for ; iter < Cfg_simu_num_iter; iter++ { if true { if block_round < Cfg_simu_num_block_round { // NOTE: Propagating blocks from here is a // simplification/HACK: it implies that we have // knowledge of when messaging due to previous // activity (blocks and connections) has // stopped. Again, we make blocks from here for // debugging and testing only. //x := secp256k1.RandByte(888) // Random data in SIMU. x := make([]byte, 888) mathrand.Read(x) h := cipher.SumSHA256(x) // Its hash. //x_alt := secp256k1.RandByte(888) // Random data in SIMU. x_alt := make([]byte, 888) mathrand.Read(x) h_alt := cipher.SumSHA256(x_alt) // Its hash. global_seqno2h[hack_global_seqno] = h global_seqno2h_alt[hack_global_seqno] = h_alt indices := get_random_index_subset(Cfg_simu_num_node, Cfg_simu_num_blockmaker) if Cfg_debug_show_block_maker { fmt.Printf("block_round=%d, Random indices of block-"+ "makers: %v\n", block_round, indices) } n_forkers := int(Cfg_simu_prob_malicious * float64(len(indices))) for i := 0; i < len(indices); i++ { // TODO: Have many nodes send same block, and a few nodes // send a different block. Research the conditions under // which the block published by the majority would // dominate the other one. index := indices[i] nodePtr := X[index].GetNode() malicious := (i < n_forkers) duplicate := (mathrand.Float64() < Cfg_simu_prob_duplicate) ph := &h if malicious { ph = &h_alt } rep := 1 if duplicate { rep = 2 } // // WARNING: In a reslistic simulation, one would // need to remove the assumption of knowing global // properties such as 'hack_global_seqno' // if malicious { fmt.Printf(">>>>>> NODE (index,pubkey)=(%d,%s) is"+ " publishing ALTERNATIVE block\n", index, nodePtr.Pubkey.Hex()[:8]) } for j := 0; j < rep; j++ { // Signing same hash multipe times produces different // signatures (for a good reason). We do it // here to test if malicious re-publishing is // detected properly. propagate_hash_from_node(*ph, nodePtr, true, hack_global_seqno) } } hack_global_seqno += 1 block_round += 1 } else { done_processing_messages = true break // <<<<<<<< } } } zzz := "done" if !done_processing_messages { zzz = "***NOT done***" } fmt.Printf("Done (i) making Blocks, %s (ii) processing responses."+ " See stats on the next few lines. Used iterations=%d, unused"+ " iterations=%d. Exiting the event loop now.\n", zzz, iter, Cfg_simu_num_iter-iter) print_stat(X, iter) if Cfg_debug_node_final_state { for i, _ := range X { fmt.Printf("FILE_FinalState.txt|NODE i=%d ", i) X[i].GetNode().Print() fmt.Printf("\n") } } if Cfg_debug_node_summary { Simulate_compare_node_StateQueue(X, global_seqno2h, global_seqno2h_alt) } }
func _gpub(s cipher.SecKey) cipher.PubKey { return cipher.PubKeyFromSecKey(s) }
func addPrivateKeyCMD() gcli.Command { name := "addPrivateKey" return gcli.Command{ Name: name, Usage: "Add a private key to specific wallet", ArgsUsage: "[private key]", Description: fmt.Sprintf(`Add a private key to specific wallet, the default wallet(%s/%s) will be used if the wallet file or path is not specified`, cfg.WalletDir, cfg.DefaultWalletName), Flags: []gcli.Flag{ gcli.StringFlag{ Name: "f", Usage: "[wallet file or path] private key will be added to this wallet", }, }, OnUsageError: onCommandUsageError(name), Action: func(c *gcli.Context) error { // get private key skStr := c.Args().First() if skStr == "" { gcli.ShowSubcommandHelp(c) return nil } // get wallet file path w := c.String("f") if w == "" { w = filepath.Join(cfg.WalletDir, cfg.DefaultWalletName) } if !strings.HasSuffix(w, walletExt) { return errWalletName } // only wallet file name, no path. if filepath.Base(w) == w { w = filepath.Join(cfg.WalletDir, w) } wlt, err := wallet.Load(w) if err != nil { errorWithHelp(c, err) return nil } sk, err := cipher.SecKeyFromHex(skStr) if err != nil { return fmt.Errorf("invalid private key: %s, must be an hex string of length 64", skStr) } pk := cipher.PubKeyFromSecKey(sk) addr := cipher.AddressFromPubKey(pk) entry := wallet.WalletEntry{ Address: addr, Public: pk, Secret: sk, } if err := wlt.AddEntry(entry); err != nil { return err } dir, err := filepath.Abs(filepath.Dir(w)) if err != nil { return err } if err := wlt.Save(dir); err != nil { return errors.New("save wallet failed") } fmt.Println("success") return nil }, } // Commands = append(Commands, cmd) }
// NewVisor Creates a normal Visor given a master's public key func NewVisor(c VisorConfig) *Visor { logger.Debug("Creating new visor") // Make sure inputs are correct if c.IsMaster { logger.Debug("Visor is master") if c.BlockchainPubkey != cipher.PubKeyFromSecKey(c.BlockchainSeckey) { log.Panicf("Cannot run in master: invalid seckey for pubkey") } } db, err := historydb.NewDB() if err != nil { log.Panic(err) } history, err := historydb.New(db) if err != nil { log.Panic(err) } tree := blockdb.NewBlockTree() bc := NewBlockchain(tree, walker) bp := NewBlockchainParser(history, bc) bp.Start() bc.BindListener(bp.BlockListener) v := &Visor{ Config: c, Blockchain: bc, blockSigs: blockdb.NewBlockSigs(), Unconfirmed: NewUnconfirmedTxnPool(), history: history, bcParser: bp, } gb := bc.GetGenesisBlock() if gb == nil { v.GenesisPreconditions() b := v.Blockchain.CreateGenesisBlock(c.GenesisAddress, c.GenesisCoinVolume, c.GenesisTimestamp) gb = &b logger.Debug("create genesis block") // record the signature of genesis block if c.IsMaster { sb := v.SignBlock(*gb) v.blockSigs.Add(&sb) } else { v.blockSigs.Add(&coin.SignedBlock{ Block: *gb, Sig: c.GenesisSignature, }) } } if err := v.Blockchain.VerifySigs(c.BlockchainPubkey, v.blockSigs); err != nil { log.Panicf("Invalid block signatures: %v", err) } // db, err := historydb.NewDB() // if err != nil { // log.Panic(err) // } // v.history, err = historydb.New(db) // if err != nil { // log.Panic(err) // } // init the blockchain parser instance // v.bcParser = NewBlockchainParser(v.history, v.Blockchain) // v.StartParser() return v }