Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 4.0 KiB After Width: | Height: | Size: 4.0 KiB |
@ -0,0 +1,34 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"flag" |
||||
) |
||||
|
||||
var StartConsole bool |
||||
var StartMining bool |
||||
var UseUPnP bool |
||||
var OutboundPort string |
||||
var ShowGenesis bool |
||||
var AddPeer string |
||||
var MaxPeer int |
||||
var GenAddr bool |
||||
var UseSeed bool |
||||
var ImportKey string |
||||
var ExportKey bool |
||||
var DataDir string |
||||
|
||||
func Init() { |
||||
flag.BoolVar(&StartConsole, "c", false, "debug and testing console") |
||||
flag.BoolVar(&StartMining, "m", false, "start dagger mining") |
||||
flag.BoolVar(&ShowGenesis, "g", false, "prints genesis header and exits") |
||||
flag.BoolVar(&UseUPnP, "upnp", false, "enable UPnP support") |
||||
flag.BoolVar(&UseSeed, "seed", true, "seed peers") |
||||
flag.BoolVar(&GenAddr, "genaddr", false, "create a new priv/pub key") |
||||
flag.BoolVar(&ExportKey, "export", false, "export private key") |
||||
flag.StringVar(&OutboundPort, "p", "30303", "listening port") |
||||
flag.StringVar(&DataDir, "dir", ".ethereal", "ethereum data directory") |
||||
flag.StringVar(&ImportKey, "import", "", "imports the given private key (hex)") |
||||
flag.IntVar(&MaxPeer, "x", 5, "maximum desired peers") |
||||
|
||||
flag.Parse() |
||||
} |
@ -0,0 +1,110 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go" |
||||
"github.com/ethereum/eth-go/ethchain" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"github.com/ethereum/go-ethereum/ethereal/ui" |
||||
"github.com/ethereum/go-ethereum/utils" |
||||
"github.com/niemeyer/qml" |
||||
"log" |
||||
"os" |
||||
"os/signal" |
||||
"runtime" |
||||
) |
||||
|
||||
const Debug = true |
||||
|
||||
// Register interrupt handlers so we can stop the ethereum
|
||||
func RegisterInterupts(s *eth.Ethereum) { |
||||
// Buffered chan of one is enough
|
||||
c := make(chan os.Signal, 1) |
||||
// Notify about interrupts for now
|
||||
signal.Notify(c, os.Interrupt) |
||||
go func() { |
||||
for sig := range c { |
||||
fmt.Printf("Shutting down (%v) ... \n", sig) |
||||
|
||||
s.Stop() |
||||
} |
||||
}() |
||||
} |
||||
|
||||
func main() { |
||||
Init() |
||||
|
||||
qml.Init(nil) |
||||
|
||||
runtime.GOMAXPROCS(runtime.NumCPU()) |
||||
|
||||
ethchain.InitFees() |
||||
ethutil.ReadConfig(DataDir) |
||||
ethutil.Config.Seed = UseSeed |
||||
|
||||
// Instantiated a eth stack
|
||||
ethereum, err := eth.New(eth.CapDefault, UseUPnP) |
||||
if err != nil { |
||||
log.Println("eth start err:", err) |
||||
return |
||||
} |
||||
ethereum.Port = OutboundPort |
||||
|
||||
if GenAddr { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
|
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
utils.CreateKeyPair(true) |
||||
} |
||||
os.Exit(0) |
||||
} else { |
||||
if len(ImportKey) > 0 { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
utils.ImportPrivateKey(ImportKey) |
||||
os.Exit(0) |
||||
} |
||||
} else { |
||||
utils.CreateKeyPair(false) |
||||
} |
||||
} |
||||
|
||||
if ExportKey { |
||||
key := ethutil.Config.Db.GetKeys()[0] |
||||
fmt.Printf("%x\n", key.PrivateKey) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
if ShowGenesis { |
||||
fmt.Println(ethereum.BlockChain().Genesis()) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver) |
||||
|
||||
// Set the max peers
|
||||
ethereum.MaxPeers = MaxPeer |
||||
|
||||
gui := ethui.New(ethereum) |
||||
gui.Start() |
||||
} |
@ -1,215 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go" |
||||
"github.com/ethereum/eth-go/ethchain" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"github.com/ethereum/eth-go/ethwire" |
||||
"github.com/ethereum/go-ethereum/ui" |
||||
"github.com/niemeyer/qml" |
||||
"github.com/obscuren/secp256k1-go" |
||||
"log" |
||||
"os" |
||||
"os/signal" |
||||
"runtime" |
||||
) |
||||
|
||||
const Debug = true |
||||
|
||||
// Register interrupt handlers so we can stop the ethereum
|
||||
func RegisterInterupts(s *eth.Ethereum) { |
||||
// Buffered chan of one is enough
|
||||
c := make(chan os.Signal, 1) |
||||
// Notify about interrupts for now
|
||||
signal.Notify(c, os.Interrupt) |
||||
go func() { |
||||
for sig := range c { |
||||
fmt.Printf("Shutting down (%v) ... \n", sig) |
||||
|
||||
s.Stop() |
||||
} |
||||
}() |
||||
} |
||||
|
||||
func CreateKeyPair(force bool) { |
||||
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) |
||||
if len(data) == 0 || force { |
||||
pub, prv := secp256k1.GenerateKeyPair() |
||||
pair := ðutil.Key{PrivateKey: prv, PublicKey: pub} |
||||
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) |
||||
|
||||
fmt.Printf(` |
||||
Generating new address and keypair. |
||||
Please keep your keys somewhere save. |
||||
|
||||
++++++++++++++++ KeyRing +++++++++++++++++++ |
||||
addr: %x |
||||
prvk: %x |
||||
pubk: %x |
||||
++++++++++++++++++++++++++++++++++++++++++++ |
||||
|
||||
`, pair.Address(), prv, pub) |
||||
|
||||
} |
||||
} |
||||
|
||||
func ImportPrivateKey(prvKey string) { |
||||
key := ethutil.FromHex(prvKey) |
||||
msg := []byte("tmp") |
||||
// Couldn't think of a better way to get the pub key
|
||||
sig, _ := secp256k1.Sign(msg, key) |
||||
pub, _ := secp256k1.RecoverPubkey(msg, sig) |
||||
pair := ðutil.Key{PrivateKey: key, PublicKey: pub} |
||||
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) |
||||
|
||||
fmt.Printf(` |
||||
Importing private key |
||||
|
||||
++++++++++++++++ KeyRing +++++++++++++++++++ |
||||
addr: %x |
||||
prvk: %x |
||||
pubk: %x |
||||
++++++++++++++++++++++++++++++++++++++++++++ |
||||
|
||||
`, pair.Address(), key, pub) |
||||
} |
||||
|
||||
func main() { |
||||
Init() |
||||
|
||||
// Qt has to be initialized in the main thread or it will throw errors
|
||||
// It has to be called BEFORE setting the maximum procs.
|
||||
if UseGui { |
||||
qml.Init(nil) |
||||
} |
||||
|
||||
runtime.GOMAXPROCS(runtime.NumCPU()) |
||||
|
||||
ethchain.InitFees() |
||||
ethutil.ReadConfig(DataDir) |
||||
ethutil.Config.Seed = UseSeed |
||||
|
||||
// Instantiated a eth stack
|
||||
ethereum, err := eth.New(eth.CapDefault, UseUPnP) |
||||
if err != nil { |
||||
log.Println("eth start err:", err) |
||||
return |
||||
} |
||||
ethereum.Port = OutboundPort |
||||
|
||||
if GenAddr { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
|
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
CreateKeyPair(true) |
||||
} |
||||
os.Exit(0) |
||||
} else { |
||||
if len(ImportKey) > 0 { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
ImportPrivateKey(ImportKey) |
||||
os.Exit(0) |
||||
} |
||||
} else { |
||||
CreateKeyPair(false) |
||||
} |
||||
} |
||||
|
||||
if ExportKey { |
||||
key := ethutil.Config.Db.GetKeys()[0] |
||||
fmt.Printf("%x\n", key.PrivateKey) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
if ShowGenesis { |
||||
fmt.Println(ethereum.BlockChain().Genesis()) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver) |
||||
|
||||
// Set the max peers
|
||||
ethereum.MaxPeers = MaxPeer |
||||
|
||||
if StartConsole { |
||||
err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm) |
||||
// Error is OK if the error is ErrExist
|
||||
if err != nil && !os.IsExist(err) { |
||||
log.Panic("Unable to create EXECPATH:", err) |
||||
} |
||||
|
||||
console := NewConsole(ethereum) |
||||
go console.Start() |
||||
} |
||||
|
||||
if UseGui { |
||||
gui := ethui.New(ethereum) |
||||
gui.Start() |
||||
//ethereum.Stop()
|
||||
} else { |
||||
RegisterInterupts(ethereum) |
||||
ethereum.Start() |
||||
|
||||
if StartMining { |
||||
log.Printf("Miner started\n") |
||||
|
||||
// Fake block mining. It broadcasts a new block every 5 seconds
|
||||
go func() { |
||||
pow := ðchain.EasyPow{} |
||||
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) |
||||
keyRing := ethutil.NewValueFromBytes(data) |
||||
addr := keyRing.Get(1).Bytes() |
||||
|
||||
for { |
||||
txs := ethereum.TxPool().Flush() |
||||
// Create a new block which we're going to mine
|
||||
block := ethereum.BlockChain().NewBlock(addr, txs) |
||||
log.Println("Mining on new block. Includes", len(block.Transactions()), "transactions") |
||||
// Apply all transactions to the block
|
||||
ethereum.StateManager().ApplyTransactions(block, block.Transactions()) |
||||
|
||||
ethereum.StateManager().Prepare(block.State(), block.State()) |
||||
ethereum.StateManager().AccumelateRewards(block) |
||||
|
||||
// Search the nonce
|
||||
block.Nonce = pow.Search(block) |
||||
ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) |
||||
|
||||
ethereum.StateManager().PrepareDefault(block) |
||||
err := ethereum.StateManager().ProcessBlock(block) |
||||
if err != nil { |
||||
log.Println(err) |
||||
} else { |
||||
log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockChain().CurrentBlock) |
||||
log.Printf("🔨 Mined block %x\n", block.Hash()) |
||||
} |
||||
} |
||||
}() |
||||
} |
||||
|
||||
// Wait for shutdown
|
||||
ethereum.WaitForShutdown() |
||||
} |
||||
} |
@ -0,0 +1,158 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go" |
||||
"github.com/ethereum/eth-go/ethchain" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"github.com/ethereum/eth-go/ethwire" |
||||
"github.com/ethereum/go-ethereum/utils" |
||||
"log" |
||||
"os" |
||||
"os/signal" |
||||
"runtime" |
||||
) |
||||
|
||||
const Debug = true |
||||
|
||||
// Register interrupt handlers so we can stop the ethereum
|
||||
func RegisterInterupts(s *eth.Ethereum) { |
||||
// Buffered chan of one is enough
|
||||
c := make(chan os.Signal, 1) |
||||
// Notify about interrupts for now
|
||||
signal.Notify(c, os.Interrupt) |
||||
go func() { |
||||
for sig := range c { |
||||
fmt.Printf("Shutting down (%v) ... \n", sig) |
||||
|
||||
s.Stop() |
||||
} |
||||
}() |
||||
} |
||||
|
||||
func main() { |
||||
Init() |
||||
|
||||
runtime.GOMAXPROCS(runtime.NumCPU()) |
||||
|
||||
ethchain.InitFees() |
||||
ethutil.ReadConfig(DataDir) |
||||
ethutil.Config.Seed = UseSeed |
||||
|
||||
// Instantiated a eth stack
|
||||
ethereum, err := eth.New(eth.CapDefault, UseUPnP) |
||||
if err != nil { |
||||
log.Println("eth start err:", err) |
||||
return |
||||
} |
||||
ethereum.Port = OutboundPort |
||||
|
||||
if GenAddr { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
|
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
utils.CreateKeyPair(true) |
||||
} |
||||
os.Exit(0) |
||||
} else { |
||||
if len(ImportKey) > 0 { |
||||
fmt.Println("This action overwrites your old private key. Are you sure? (y/n)") |
||||
var r string |
||||
fmt.Scanln(&r) |
||||
for ; ; fmt.Scanln(&r) { |
||||
if r == "n" || r == "y" { |
||||
break |
||||
} else { |
||||
fmt.Printf("Yes or no?", r) |
||||
} |
||||
} |
||||
|
||||
if r == "y" { |
||||
utils.ImportPrivateKey(ImportKey) |
||||
os.Exit(0) |
||||
} |
||||
} else { |
||||
utils.CreateKeyPair(false) |
||||
} |
||||
} |
||||
|
||||
if ExportKey { |
||||
key := ethutil.Config.Db.GetKeys()[0] |
||||
fmt.Printf("%x\n", key.PrivateKey) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
if ShowGenesis { |
||||
fmt.Println(ethereum.BlockChain().Genesis()) |
||||
os.Exit(0) |
||||
} |
||||
|
||||
log.Printf("Starting Ethereum v%s\n", ethutil.Config.Ver) |
||||
|
||||
// Set the max peers
|
||||
ethereum.MaxPeers = MaxPeer |
||||
|
||||
if StartConsole { |
||||
err := os.Mkdir(ethutil.Config.ExecPath, os.ModePerm) |
||||
// Error is OK if the error is ErrExist
|
||||
if err != nil && !os.IsExist(err) { |
||||
log.Panic("Unable to create EXECPATH:", err) |
||||
} |
||||
|
||||
console := NewConsole(ethereum) |
||||
go console.Start() |
||||
} |
||||
|
||||
RegisterInterupts(ethereum) |
||||
ethereum.Start() |
||||
|
||||
if StartMining { |
||||
log.Printf("Miner started\n") |
||||
|
||||
// Fake block mining. It broadcasts a new block every 5 seconds
|
||||
go func() { |
||||
pow := ðchain.EasyPow{} |
||||
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) |
||||
keyRing := ethutil.NewValueFromBytes(data) |
||||
addr := keyRing.Get(1).Bytes() |
||||
|
||||
for { |
||||
txs := ethereum.TxPool().Flush() |
||||
// Create a new block which we're going to mine
|
||||
block := ethereum.BlockChain().NewBlock(addr, txs) |
||||
log.Println("Mining on new block. Includes", len(block.Transactions()), "transactions") |
||||
// Apply all transactions to the block
|
||||
ethereum.StateManager().ApplyTransactions(block, block.Transactions()) |
||||
|
||||
ethereum.StateManager().Prepare(block.State(), block.State()) |
||||
ethereum.StateManager().AccumelateRewards(block) |
||||
|
||||
// Search the nonce
|
||||
block.Nonce = pow.Search(block) |
||||
ethereum.Broadcast(ethwire.MsgBlockTy, []interface{}{block.Value().Val}) |
||||
|
||||
ethereum.StateManager().PrepareDefault(block) |
||||
err := ethereum.StateManager().ProcessBlock(block) |
||||
if err != nil { |
||||
log.Println(err) |
||||
} else { |
||||
log.Println("\n+++++++ MINED BLK +++++++\n", ethereum.BlockChain().CurrentBlock) |
||||
log.Printf("🔨 Mined block %x\n", block.Hash()) |
||||
} |
||||
} |
||||
}() |
||||
} |
||||
|
||||
// Wait for shutdown
|
||||
ethereum.WaitForShutdown() |
||||
} |
@ -1,35 +0,0 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"fmt" |
||||
"testing" |
||||
) |
||||
|
||||
type TestSource struct { |
||||
Inputs map[string]string |
||||
Expectation string |
||||
} |
||||
|
||||
func NewTestSource(source string) *TestSource { |
||||
s := &TestSource{} |
||||
err := json.Unmarshal([]byte(source), s) |
||||
if err != nil { |
||||
fmt.Println(err) |
||||
} |
||||
|
||||
return s |
||||
} |
||||
|
||||
type TestRunner struct { |
||||
source *TestSource |
||||
} |
||||
|
||||
func NewTestRunner(t *testing.T) *TestRunner { |
||||
return &TestRunner{} |
||||
} |
||||
|
||||
func (runner *TestRunner) RunFromString(input string, Cb func(*TestSource)) { |
||||
source := NewTestSource(input) |
||||
Cb(source) |
||||
} |
@ -1,36 +0,0 @@ |
||||
package main |
||||
|
||||
/* |
||||
import ( |
||||
"encoding/hex" |
||||
_ "fmt" |
||||
"github.com/ethereum/ethdb-go" |
||||
"github.com/ethereum/ethutil-go" |
||||
"testing" |
||||
) |
||||
|
||||
var testsource = ` |
||||
{ |
||||
"inputs":{ |
||||
"doe": "reindeer", |
||||
"dog": "puppy", |
||||
"dogglesworth": "cat" |
||||
}, |
||||
"expectation":"e378927bfc1bd4f01a2e8d9f59bd18db8a208bb493ac0b00f93ce51d4d2af76c" |
||||
}` |
||||
|
||||
func TestTestRunner(t *testing.T) { |
||||
db, _ := ethdb.NewMemDatabase() |
||||
trie := ethutil.NewTrie(db, "") |
||||
|
||||
runner := NewTestRunner(t) |
||||
runner.RunFromString(testsource, func(source *TestSource) { |
||||
for key, value := range source.Inputs { |
||||
trie.Update(key, value) |
||||
} |
||||
if hex.EncodeToString(trie.Root.([]byte)) != source.Expectation { |
||||
t.Error("trie root did not match") |
||||
} |
||||
}) |
||||
} |
||||
*/ |
@ -1,33 +0,0 @@ |
||||
package main |
||||
|
||||
/* |
||||
|
||||
import ( |
||||
_"fmt" |
||||
) |
||||
|
||||
// This will eventually go away
|
||||
var Db *MemDatabase |
||||
|
||||
func Testing() { |
||||
db, _ := NewMemDatabase() |
||||
Db = db |
||||
|
||||
bm := NewBlockManager() |
||||
|
||||
tx := NewTransaction("\x00", 20, []string{"PUSH"}) |
||||
txData := tx.RlpEncode() |
||||
//fmt.Printf("%q\n", txData)
|
||||
|
||||
copyTx := &Transaction{} |
||||
copyTx.RlpDecode(txData) |
||||
//fmt.Println(tx)
|
||||
//fmt.Println(copyTx)
|
||||
|
||||
tx2 := NewTransaction("\x00", 20, []string{"SET 10 6", "LD 10 10"}) |
||||
|
||||
blck := CreateTestBlock([]*Transaction{tx2, tx}) |
||||
|
||||
bm.ProcessBlock( blck ) |
||||
} |
||||
*/ |
@ -0,0 +1,50 @@ |
||||
package utils |
||||
|
||||
import ( |
||||
"fmt" |
||||
"github.com/ethereum/eth-go/ethutil" |
||||
"github.com/obscuren/secp256k1-go" |
||||
) |
||||
|
||||
func CreateKeyPair(force bool) { |
||||
data, _ := ethutil.Config.Db.Get([]byte("KeyRing")) |
||||
if len(data) == 0 || force { |
||||
pub, prv := secp256k1.GenerateKeyPair() |
||||
pair := ðutil.Key{PrivateKey: prv, PublicKey: pub} |
||||
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) |
||||
|
||||
fmt.Printf(` |
||||
Generating new address and keypair. |
||||
Please keep your keys somewhere save. |
||||
|
||||
++++++++++++++++ KeyRing +++++++++++++++++++ |
||||
addr: %x |
||||
prvk: %x |
||||
pubk: %x |
||||
++++++++++++++++++++++++++++++++++++++++++++ |
||||
|
||||
`, pair.Address(), prv, pub) |
||||
|
||||
} |
||||
} |
||||
|
||||
func ImportPrivateKey(prvKey string) { |
||||
key := ethutil.FromHex(prvKey) |
||||
msg := []byte("tmp") |
||||
// Couldn't think of a better way to get the pub key
|
||||
sig, _ := secp256k1.Sign(msg, key) |
||||
pub, _ := secp256k1.RecoverPubkey(msg, sig) |
||||
pair := ðutil.Key{PrivateKey: key, PublicKey: pub} |
||||
ethutil.Config.Db.Put([]byte("KeyRing"), pair.RlpEncode()) |
||||
|
||||
fmt.Printf(` |
||||
Importing private key |
||||
|
||||
++++++++++++++++ KeyRing +++++++++++++++++++ |
||||
addr: %x |
||||
prvk: %x |
||||
pubk: %x |
||||
++++++++++++++++++++++++++++++++++++++++++++ |
||||
|
||||
`, pair.Address(), key, pub) |
||||
} |