Merge pull request #17 from ethereum/master

Pull go-ethereum 1.8.11
This commit is contained in:
ledgerwatch 2018-06-12 16:53:19 +01:00 committed by GitHub
commit 6245a13482
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 524 additions and 272 deletions

View file

@ -1 +1 @@
1.8.11 1.8.12

View file

@ -0,0 +1,72 @@
package main
import (
"fmt"
"io/ioutil"
"strings"
"github.com/ethereum/go-ethereum/accounts/keystore"
"github.com/ethereum/go-ethereum/cmd/utils"
"gopkg.in/urfave/cli.v1"
)
var newPassphraseFlag = cli.StringFlag{
Name: "newpasswordfile",
Usage: "the file that contains the new passphrase for the keyfile",
}
var commandChangePassphrase = cli.Command{
Name: "changepassphrase",
Usage: "change the passphrase on a keyfile",
ArgsUsage: "<keyfile>",
Description: `
Change the passphrase of a keyfile.`,
Flags: []cli.Flag{
passphraseFlag,
newPassphraseFlag,
},
Action: func(ctx *cli.Context) error {
keyfilepath := ctx.Args().First()
// Read key from file.
keyjson, err := ioutil.ReadFile(keyfilepath)
if err != nil {
utils.Fatalf("Failed to read the keyfile at '%s': %v", keyfilepath, err)
}
// Decrypt key with passphrase.
passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil {
utils.Fatalf("Error decrypting key: %v", err)
}
// Get a new passphrase.
fmt.Println("Please provide a new passphrase")
var newPhrase string
if passFile := ctx.String(newPassphraseFlag.Name); passFile != "" {
content, err := ioutil.ReadFile(passFile)
if err != nil {
utils.Fatalf("Failed to read new passphrase file '%s': %v", passFile, err)
}
newPhrase = strings.TrimRight(string(content), "\r\n")
} else {
newPhrase = promptPassphrase(true)
}
// Encrypt the key with the new passphrase.
newJson, err := keystore.EncryptKey(key, newPhrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil {
utils.Fatalf("Error encrypting with new passphrase: %v", err)
}
// Then write the new keyfile in place of the old one.
if err := ioutil.WriteFile(keyfilepath, newJson, 600); err != nil {
utils.Fatalf("Error writing new keyfile to disk: %v", err)
}
// Don't print anything. Just return successfully,
// producing a positive exit code.
return nil
},
}

View file

@ -90,7 +90,7 @@ If you want to encrypt an existing private key, it can be specified by setting
} }
// Encrypt key with passphrase. // Encrypt key with passphrase.
passphrase := getPassPhrase(ctx, true) passphrase := promptPassphrase(true)
keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP) keyjson, err := keystore.EncryptKey(key, passphrase, keystore.StandardScryptN, keystore.StandardScryptP)
if err != nil { if err != nil {
utils.Fatalf("Error encrypting key: %v", err) utils.Fatalf("Error encrypting key: %v", err)

View file

@ -60,7 +60,7 @@ make sure to use this feature with great caution!`,
} }
// Decrypt key with passphrase. // Decrypt key with passphrase.
passphrase := getPassPhrase(ctx, false) passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase) key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil { if err != nil {
utils.Fatalf("Error decrypting key: %v", err) utils.Fatalf("Error decrypting key: %v", err)

View file

@ -38,6 +38,7 @@ func init() {
app.Commands = []cli.Command{ app.Commands = []cli.Command{
commandGenerate, commandGenerate,
commandInspect, commandInspect,
commandChangePassphrase,
commandSignMessage, commandSignMessage,
commandVerifyMessage, commandVerifyMessage,
} }

View file

@ -62,7 +62,7 @@ To sign a message contained in a file, use the --msgfile flag.
} }
// Decrypt key with passphrase. // Decrypt key with passphrase.
passphrase := getPassPhrase(ctx, false) passphrase := getPassphrase(ctx)
key, err := keystore.DecryptKey(keyjson, passphrase) key, err := keystore.DecryptKey(keyjson, passphrase)
if err != nil { if err != nil {
utils.Fatalf("Error decrypting key: %v", err) utils.Fatalf("Error decrypting key: %v", err)

View file

@ -28,11 +28,32 @@ import (
"gopkg.in/urfave/cli.v1" "gopkg.in/urfave/cli.v1"
) )
// getPassPhrase obtains a passphrase given by the user. It first checks the // promptPassphrase prompts the user for a passphrase. Set confirmation to true
// --passphrase command line flag and ultimately prompts the user for a // to require the user to confirm the passphrase.
func promptPassphrase(confirmation bool) string {
passphrase, err := console.Stdin.PromptPassword("Passphrase: ")
if err != nil {
utils.Fatalf("Failed to read passphrase: %v", err)
}
if confirmation {
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
if err != nil {
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
}
if passphrase != confirm {
utils.Fatalf("Passphrases do not match")
}
}
return passphrase
}
// getPassphrase obtains a passphrase given by the user. It first checks the
// --passfile command line flag and ultimately prompts the user for a
// passphrase. // passphrase.
func getPassPhrase(ctx *cli.Context, confirmation bool) string { func getPassphrase(ctx *cli.Context) string {
// Look for the --passphrase flag. // Look for the --passwordfile flag.
passphraseFile := ctx.String(passphraseFlag.Name) passphraseFile := ctx.String(passphraseFlag.Name)
if passphraseFile != "" { if passphraseFile != "" {
content, err := ioutil.ReadFile(passphraseFile) content, err := ioutil.ReadFile(passphraseFile)
@ -44,20 +65,7 @@ func getPassPhrase(ctx *cli.Context, confirmation bool) string {
} }
// Otherwise prompt the user for the passphrase. // Otherwise prompt the user for the passphrase.
passphrase, err := console.Stdin.PromptPassword("Passphrase: ") return promptPassphrase(false)
if err != nil {
utils.Fatalf("Failed to read passphrase: %v", err)
}
if confirmation {
confirm, err := console.Stdin.PromptPassword("Repeat passphrase: ")
if err != nil {
utils.Fatalf("Failed to read passphrase confirmation: %v", err)
}
if passphrase != confirm {
utils.Fatalf("Passphrases do not match")
}
}
return passphrase
} }
// signHash is a helper function that calculates a hash for the given message // signHash is a helper function that calculates a hash for the given message

View file

@ -140,8 +140,8 @@ func processArgs() {
} }
if *asymmetricMode && len(*argPub) > 0 { if *asymmetricMode && len(*argPub) > 0 {
pub = crypto.ToECDSAPub(common.FromHex(*argPub)) var err error
if !isKeyValid(pub) { if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
utils.Fatalf("invalid public key") utils.Fatalf("invalid public key")
} }
} }
@ -321,10 +321,6 @@ func startServer() error {
return nil return nil
} }
func isKeyValid(k *ecdsa.PublicKey) bool {
return k.X != nil && k.Y != nil
}
func configureNode() { func configureNode() {
var err error var err error
var p2pAccept bool var p2pAccept bool
@ -340,9 +336,8 @@ func configureNode() {
if b == nil { if b == nil {
utils.Fatalf("Error: can not convert hexadecimal string") utils.Fatalf("Error: can not convert hexadecimal string")
} }
pub = crypto.ToECDSAPub(b) if pub, err = crypto.UnmarshalPubkey(b); err != nil {
if !isKeyValid(pub) { utils.Fatalf("Error: invalid peer public key")
utils.Fatalf("Error: invalid public key")
} }
} }
} }

View file

@ -1392,27 +1392,21 @@ func (bc *BlockChain) update() {
} }
} }
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
type BadBlockArgs struct {
Hash common.Hash `json:"hash"`
Header *types.Header `json:"header"`
}
// BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network // BadBlocks returns a list of the last 'bad blocks' that the client has seen on the network
func (bc *BlockChain) BadBlocks() ([]BadBlockArgs, error) { func (bc *BlockChain) BadBlocks() []*types.Block {
headers := make([]BadBlockArgs, 0, bc.badBlocks.Len()) blocks := make([]*types.Block, 0, bc.badBlocks.Len())
for _, hash := range bc.badBlocks.Keys() { for _, hash := range bc.badBlocks.Keys() {
if hdr, exist := bc.badBlocks.Peek(hash); exist { if blk, exist := bc.badBlocks.Peek(hash); exist {
header := hdr.(*types.Header) block := blk.(*types.Block)
headers = append(headers, BadBlockArgs{header.Hash(), header}) blocks = append(blocks, block)
} }
} }
return headers, nil return blocks
} }
// addBadBlock adds a bad block to the bad-block LRU cache // addBadBlock adds a bad block to the bad-block LRU cache
func (bc *BlockChain) addBadBlock(block *types.Block) { func (bc *BlockChain) addBadBlock(block *types.Block) {
bc.badBlocks.Add(block.Header().Hash(), block.Header()) bc.badBlocks.Add(block.Hash(), block)
} }
// reportBlock logs a bad block error. // reportBlock logs a bad block error.
@ -1530,6 +1524,18 @@ func (bc *BlockChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []com
return bc.hc.GetBlockHashesFromHash(hash, max) return bc.hc.GetBlockHashesFromHash(hash, max)
} }
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
// number of blocks to be individually checked before we reach the canonical chain.
//
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
func (bc *BlockChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
bc.chainmu.Lock()
defer bc.chainmu.Unlock()
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
}
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header { func (bc *BlockChain) GetHeaderByNumber(number uint64) *types.Header {

View file

@ -307,6 +307,43 @@ func (hc *HeaderChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []co
return chain return chain
} }
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
// number of blocks to be individually checked before we reach the canonical chain.
//
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
func (hc *HeaderChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
if ancestor > number {
return common.Hash{}, 0
}
if ancestor == 1 {
// in this case it is cheaper to just read the header
if header := hc.GetHeader(hash, number); header != nil {
return header.ParentHash, number - 1
} else {
return common.Hash{}, 0
}
}
for ancestor != 0 {
if rawdb.ReadCanonicalHash(hc.chainDb, number) == hash {
number -= ancestor
return rawdb.ReadCanonicalHash(hc.chainDb, number), number
}
if *maxNonCanonical == 0 {
return common.Hash{}, 0
}
*maxNonCanonical--
ancestor--
header := hc.GetHeader(hash, number)
if header == nil {
return common.Hash{}, 0
}
hash = header.ParentHash
number--
}
return hash, number
}
// GetTd retrieves a block's total difficulty in the canonical chain from the // GetTd retrieves a block's total difficulty in the canonical chain from the
// database by hash and number, caching it if found. // database by hash and number, caching it if found.
func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int { func (hc *HeaderChain) GetTd(hash common.Hash, number uint64) *big.Int {

View file

@ -29,7 +29,7 @@ import (
// ReadCanonicalHash retrieves the hash assigned to a canonical block number. // ReadCanonicalHash retrieves the hash assigned to a canonical block number.
func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash { func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)) data, _ := db.Get(headerHashKey(number))
if len(data) == 0 { if len(data) == 0 {
return common.Hash{} return common.Hash{}
} }
@ -38,22 +38,21 @@ func ReadCanonicalHash(db DatabaseReader, number uint64) common.Hash {
// WriteCanonicalHash stores the hash assigned to a canonical block number. // WriteCanonicalHash stores the hash assigned to a canonical block number.
func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) { func WriteCanonicalHash(db DatabaseWriter, hash common.Hash, number uint64) {
key := append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...) if err := db.Put(headerHashKey(number), hash.Bytes()); err != nil {
if err := db.Put(key, hash.Bytes()); err != nil {
log.Crit("Failed to store number to hash mapping", "err", err) log.Crit("Failed to store number to hash mapping", "err", err)
} }
} }
// DeleteCanonicalHash removes the number to hash canonical mapping. // DeleteCanonicalHash removes the number to hash canonical mapping.
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) { func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)); err != nil { if err := db.Delete(headerHashKey(number)); err != nil {
log.Crit("Failed to delete number to hash mapping", "err", err) log.Crit("Failed to delete number to hash mapping", "err", err)
} }
} }
// ReadHeaderNumber returns the header number assigned to a hash. // ReadHeaderNumber returns the header number assigned to a hash.
func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 { func ReadHeaderNumber(db DatabaseReader, hash common.Hash) *uint64 {
data, _ := db.Get(append(headerNumberPrefix, hash.Bytes()...)) data, _ := db.Get(headerNumberKey(hash))
if len(data) != 8 { if len(data) != 8 {
return nil return nil
} }
@ -129,14 +128,13 @@ func WriteFastTrieProgress(db DatabaseWriter, count uint64) {
// ReadHeaderRLP retrieves a block header in its raw RLP database encoding. // ReadHeaderRLP retrieves a block header in its raw RLP database encoding.
func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { func ReadHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) data, _ := db.Get(headerKey(number, hash))
return data return data
} }
// HasHeader verifies the existence of a block header corresponding to the hash. // HasHeader verifies the existence of a block header corresponding to the hash.
func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool { func HasHeader(db DatabaseReader, hash common.Hash, number uint64) bool {
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) if has, err := db.Has(headerKey(number, hash)); !has || err != nil {
if has, err := db.Has(key); !has || err != nil {
return false return false
} }
return true return true
@ -161,11 +159,11 @@ func ReadHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Heade
func WriteHeader(db DatabaseWriter, header *types.Header) { func WriteHeader(db DatabaseWriter, header *types.Header) {
// Write the hash -> number mapping // Write the hash -> number mapping
var ( var (
hash = header.Hash().Bytes() hash = header.Hash()
number = header.Number.Uint64() number = header.Number.Uint64()
encoded = encodeBlockNumber(number) encoded = encodeBlockNumber(number)
) )
key := append(headerNumberPrefix, hash...) key := headerNumberKey(hash)
if err := db.Put(key, encoded); err != nil { if err := db.Put(key, encoded); err != nil {
log.Crit("Failed to store hash to number mapping", "err", err) log.Crit("Failed to store hash to number mapping", "err", err)
} }
@ -174,7 +172,7 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
if err != nil { if err != nil {
log.Crit("Failed to RLP encode header", "err", err) log.Crit("Failed to RLP encode header", "err", err)
} }
key = append(append(headerPrefix, encoded...), hash...) key = headerKey(number, hash)
if err := db.Put(key, data); err != nil { if err := db.Put(key, data); err != nil {
log.Crit("Failed to store header", "err", err) log.Crit("Failed to store header", "err", err)
} }
@ -182,32 +180,30 @@ func WriteHeader(db DatabaseWriter, header *types.Header) {
// DeleteHeader removes all block header data associated with a hash. // DeleteHeader removes all block header data associated with a hash.
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) { func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil { if err := db.Delete(headerKey(number, hash)); err != nil {
log.Crit("Failed to delete header", "err", err) log.Crit("Failed to delete header", "err", err)
} }
if err := db.Delete(append(headerNumberPrefix, hash.Bytes()...)); err != nil { if err := db.Delete(headerNumberKey(hash)); err != nil {
log.Crit("Failed to delete hash to number mapping", "err", err) log.Crit("Failed to delete hash to number mapping", "err", err)
} }
} }
// ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding. // ReadBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue { func ReadBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
data, _ := db.Get(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)) data, _ := db.Get(blockBodyKey(number, hash))
return data return data
} }
// WriteBodyRLP stores an RLP encoded block body into the database. // WriteBodyRLP stores an RLP encoded block body into the database.
func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) { func WriteBodyRLP(db DatabaseWriter, hash common.Hash, number uint64, rlp rlp.RawValue) {
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) if err := db.Put(blockBodyKey(number, hash), rlp); err != nil {
if err := db.Put(key, rlp); err != nil {
log.Crit("Failed to store block body", "err", err) log.Crit("Failed to store block body", "err", err)
} }
} }
// HasBody verifies the existence of a block body corresponding to the hash. // HasBody verifies the existence of a block body corresponding to the hash.
func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool { func HasBody(db DatabaseReader, hash common.Hash, number uint64) bool {
key := append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...) if has, err := db.Has(blockBodyKey(number, hash)); !has || err != nil {
if has, err := db.Has(key); !has || err != nil {
return false return false
} }
return true return true
@ -238,14 +234,14 @@ func WriteBody(db DatabaseWriter, hash common.Hash, number uint64, body *types.B
// DeleteBody removes all block body data associated with a hash. // DeleteBody removes all block body data associated with a hash.
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) { func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil { if err := db.Delete(blockBodyKey(number, hash)); err != nil {
log.Crit("Failed to delete block body", "err", err) log.Crit("Failed to delete block body", "err", err)
} }
} }
// ReadTd retrieves a block's total difficulty corresponding to the hash. // ReadTd retrieves a block's total difficulty corresponding to the hash.
func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int { func ReadTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), headerTDSuffix...)) data, _ := db.Get(headerTDKey(number, hash))
if len(data) == 0 { if len(data) == 0 {
return nil return nil
} }
@ -263,15 +259,14 @@ func WriteTd(db DatabaseWriter, hash common.Hash, number uint64, td *big.Int) {
if err != nil { if err != nil {
log.Crit("Failed to RLP encode block total difficulty", "err", err) log.Crit("Failed to RLP encode block total difficulty", "err", err)
} }
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...) if err := db.Put(headerTDKey(number, hash), data); err != nil {
if err := db.Put(key, data); err != nil {
log.Crit("Failed to store block total difficulty", "err", err) log.Crit("Failed to store block total difficulty", "err", err)
} }
} }
// DeleteTd removes all block total difficulty data associated with a hash. // DeleteTd removes all block total difficulty data associated with a hash.
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) { func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), headerTDSuffix...)); err != nil { if err := db.Delete(headerTDKey(number, hash)); err != nil {
log.Crit("Failed to delete block total difficulty", "err", err) log.Crit("Failed to delete block total difficulty", "err", err)
} }
} }
@ -279,7 +274,7 @@ func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
// ReadReceipts retrieves all the transaction receipts belonging to a block. // ReadReceipts retrieves all the transaction receipts belonging to a block.
func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts { func ReadReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
// Retrieve the flattened receipt slice // Retrieve the flattened receipt slice
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...)) data, _ := db.Get(blockReceiptsKey(number, hash))
if len(data) == 0 { if len(data) == 0 {
return nil return nil
} }
@ -308,15 +303,14 @@ func WriteReceipts(db DatabaseWriter, hash common.Hash, number uint64, receipts
log.Crit("Failed to encode block receipts", "err", err) log.Crit("Failed to encode block receipts", "err", err)
} }
// Store the flattened receipt slice // Store the flattened receipt slice
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...) if err := db.Put(blockReceiptsKey(number, hash), bytes); err != nil {
if err := db.Put(key, bytes); err != nil {
log.Crit("Failed to store block receipts", "err", err) log.Crit("Failed to store block receipts", "err", err)
} }
} }
// DeleteReceipts removes all receipt data associated with a block hash. // DeleteReceipts removes all receipt data associated with a block hash.
func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) { func DeleteReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
if err := db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)); err != nil { if err := db.Delete(blockReceiptsKey(number, hash)); err != nil {
log.Crit("Failed to delete block receipts", "err", err) log.Crit("Failed to delete block receipts", "err", err)
} }
} }

View file

@ -17,8 +17,6 @@
package rawdb package rawdb
import ( import (
"encoding/binary"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -28,7 +26,7 @@ import (
// ReadTxLookupEntry retrieves the positional metadata associated with a transaction // ReadTxLookupEntry retrieves the positional metadata associated with a transaction
// hash to allow retrieving the transaction or receipt by hash. // hash to allow retrieving the transaction or receipt by hash.
func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) { func ReadTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
data, _ := db.Get(append(txLookupPrefix, hash.Bytes()...)) data, _ := db.Get(txLookupKey(hash))
if len(data) == 0 { if len(data) == 0 {
return common.Hash{}, 0, 0 return common.Hash{}, 0, 0
} }
@ -53,7 +51,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
if err != nil { if err != nil {
log.Crit("Failed to encode transaction lookup entry", "err", err) log.Crit("Failed to encode transaction lookup entry", "err", err)
} }
if err := db.Put(append(txLookupPrefix, tx.Hash().Bytes()...), data); err != nil { if err := db.Put(txLookupKey(tx.Hash()), data); err != nil {
log.Crit("Failed to store transaction lookup entry", "err", err) log.Crit("Failed to store transaction lookup entry", "err", err)
} }
} }
@ -61,7 +59,7 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
// DeleteTxLookupEntry removes all transaction data associated with a hash. // DeleteTxLookupEntry removes all transaction data associated with a hash.
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) { func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
db.Delete(append(txLookupPrefix, hash.Bytes()...)) db.Delete(txLookupKey(hash))
} }
// ReadTransaction retrieves a specific transaction from the database, along with // ReadTransaction retrieves a specific transaction from the database, along with
@ -97,23 +95,13 @@ func ReadReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Ha
// ReadBloomBits retrieves the compressed bloom bit vector belonging to the given // ReadBloomBits retrieves the compressed bloom bit vector belonging to the given
// section and bit index from the. // section and bit index from the.
func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) { func ReadBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) ([]byte, error) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) return db.Get(bloomBitsKey(bit, section, head))
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
return db.Get(key)
} }
// WriteBloomBits stores the compressed bloom bits vector belonging to the given // WriteBloomBits stores the compressed bloom bits vector belonging to the given
// section and bit index. // section and bit index.
func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) { func WriteBloomBits(db DatabaseWriter, bit uint, section uint64, head common.Hash, bits []byte) {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...) if err := db.Put(bloomBitsKey(bit, section, head), bits); err != nil {
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
if err := db.Put(key, bits); err != nil {
log.Crit("Failed to store bloom bits", "err", err) log.Crit("Failed to store bloom bits", "err", err)
} }
} }

View file

@ -45,7 +45,7 @@ func WriteDatabaseVersion(db DatabaseWriter, version int) {
// ReadChainConfig retrieves the consensus settings based on the given genesis hash. // ReadChainConfig retrieves the consensus settings based on the given genesis hash.
func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig { func ReadChainConfig(db DatabaseReader, hash common.Hash) *params.ChainConfig {
data, _ := db.Get(append(configPrefix, hash[:]...)) data, _ := db.Get(configKey(hash))
if len(data) == 0 { if len(data) == 0 {
return nil return nil
} }
@ -66,14 +66,14 @@ func WriteChainConfig(db DatabaseWriter, hash common.Hash, cfg *params.ChainConf
if err != nil { if err != nil {
log.Crit("Failed to JSON encode chain config", "err", err) log.Crit("Failed to JSON encode chain config", "err", err)
} }
if err := db.Put(append(configPrefix, hash[:]...), data); err != nil { if err := db.Put(configKey(hash), data); err != nil {
log.Crit("Failed to store chain config", "err", err) log.Crit("Failed to store chain config", "err", err)
} }
} }
// ReadPreimage retrieves a single preimage of the provided hash. // ReadPreimage retrieves a single preimage of the provided hash.
func ReadPreimage(db DatabaseReader, hash common.Hash) []byte { func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
data, _ := db.Get(append(preimagePrefix, hash.Bytes()...)) data, _ := db.Get(preimageKey(hash))
return data return data
} }
@ -81,7 +81,7 @@ func ReadPreimage(db DatabaseReader, hash common.Hash) []byte {
// current block number, and is used for debug messages only. // current block number, and is used for debug messages only.
func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) { func WritePreimages(db DatabaseWriter, number uint64, preimages map[common.Hash][]byte) {
for hash, preimage := range preimages { for hash, preimage := range preimages {
if err := db.Put(append(preimagePrefix, hash.Bytes()...), preimage); err != nil { if err := db.Put(preimageKey(hash), preimage); err != nil {
log.Crit("Failed to store trie preimage", "err", err) log.Crit("Failed to store trie preimage", "err", err)
} }
} }

View file

@ -77,3 +77,58 @@ func encodeBlockNumber(number uint64) []byte {
binary.BigEndian.PutUint64(enc, number) binary.BigEndian.PutUint64(enc, number)
return enc return enc
} }
// headerKey = headerPrefix + num (uint64 big endian) + hash
func headerKey(number uint64, hash common.Hash) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}
// headerTDKey = headerPrefix + num (uint64 big endian) + hash + headerTDSuffix
func headerTDKey(number uint64, hash common.Hash) []byte {
return append(headerKey(number, hash), headerTDSuffix...)
}
// headerHashKey = headerPrefix + num (uint64 big endian) + headerHashSuffix
func headerHashKey(number uint64) []byte {
return append(append(headerPrefix, encodeBlockNumber(number)...), headerHashSuffix...)
}
// headerNumberKey = headerNumberPrefix + hash
func headerNumberKey(hash common.Hash) []byte {
return append(headerNumberPrefix, hash.Bytes()...)
}
// blockBodyKey = blockBodyPrefix + num (uint64 big endian) + hash
func blockBodyKey(number uint64, hash common.Hash) []byte {
return append(append(blockBodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}
// blockReceiptsKey = blockReceiptsPrefix + num (uint64 big endian) + hash
func blockReceiptsKey(number uint64, hash common.Hash) []byte {
return append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
}
// txLookupKey = txLookupPrefix + hash
func txLookupKey(hash common.Hash) []byte {
return append(txLookupPrefix, hash.Bytes()...)
}
// bloomBitsKey = bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash
func bloomBitsKey(bit uint, section uint64, hash common.Hash) []byte {
key := append(append(bloomBitsPrefix, make([]byte, 10)...), hash.Bytes()...)
binary.BigEndian.PutUint16(key[1:], uint16(bit))
binary.BigEndian.PutUint64(key[3:], section)
return key
}
// preimageKey = preimagePrefix + hash
func preimageKey(hash common.Hash) []byte {
return append(preimagePrefix, hash.Bytes()...)
}
// configKey = configPrefix + hash
func configKey(hash common.Hash) []byte {
return append(configPrefix, hash.Bytes()...)
}

View file

@ -39,6 +39,8 @@ var (
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2)) secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
) )
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
// Keccak256 calculates and returns the Keccak256 hash of the input data. // Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte { func Keccak256(data ...[]byte) []byte {
d := sha3.NewKeccak256() d := sha3.NewKeccak256()
@ -122,12 +124,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8) return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
} }
func ToECDSAPub(pub []byte) *ecdsa.PublicKey { // UnmarshalPubkey converts bytes to a secp256k1 public key.
if len(pub) == 0 { func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
return nil
}
x, y := elliptic.Unmarshal(S256(), pub) x, y := elliptic.Unmarshal(S256(), pub)
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y} if x == nil {
return nil, errInvalidPubkey
}
return &ecdsa.PublicKey{Curve: S256(), X: x, Y: y}, nil
} }
func FromECDSAPub(pub *ecdsa.PublicKey) []byte { func FromECDSAPub(pub *ecdsa.PublicKey) []byte {

View file

@ -23,9 +23,11 @@ import (
"io/ioutil" "io/ioutil"
"math/big" "math/big"
"os" "os"
"reflect"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
) )
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791" var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
@ -56,6 +58,33 @@ func BenchmarkSha3(b *testing.B) {
} }
} }
func TestUnmarshalPubkey(t *testing.T) {
key, err := UnmarshalPubkey(nil)
if err != errInvalidPubkey || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}
key, err = UnmarshalPubkey([]byte{1, 2, 3})
if err != errInvalidPubkey || key != nil {
t.Fatalf("expected error, got %v, %v", err, key)
}
var (
enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d")
dec = &ecdsa.PublicKey{
Curve: S256(),
X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"),
Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"),
}
)
key, err = UnmarshalPubkey(enc)
if err != nil {
t.Fatalf("expected no error, got %v", err)
}
if !reflect.DeepEqual(key, dec) {
t.Fatal("wrong result")
}
}
func TestSign(t *testing.T) { func TestSign(t *testing.T) {
key, _ := HexToECDSA(testPrivHex) key, _ := HexToECDSA(testPrivHex)
addr := common.HexToAddress(testAddrHex) addr := common.HexToAddress(testAddrHex)
@ -69,7 +98,7 @@ func TestSign(t *testing.T) {
if err != nil { if err != nil {
t.Errorf("ECRecover error: %s", err) t.Errorf("ECRecover error: %s", err)
} }
pubKey := ToECDSAPub(recoveredPub) pubKey, _ := UnmarshalPubkey(recoveredPub)
recoveredAddr := PubkeyToAddress(*pubKey) recoveredAddr := PubkeyToAddress(*pubKey)
if addr != recoveredAddr { if addr != recoveredAddr {
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr) t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)

View file

@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/rawdb"
"github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/miner" "github.com/ethereum/go-ethereum/miner"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
@ -351,10 +352,34 @@ func (api *PrivateDebugAPI) Preimage(ctx context.Context, hash common.Hash) (hex
return nil, errors.New("unknown preimage") return nil, errors.New("unknown preimage")
} }
// BadBlockArgs represents the entries in the list returned when bad blocks are queried.
type BadBlockArgs struct {
Hash common.Hash `json:"hash"`
Block map[string]interface{} `json:"block"`
RLP string `json:"rlp"`
}
// GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network // GetBadBLocks returns a list of the last 'bad blocks' that the client has seen on the network
// and returns them as a JSON list of block-hashes // and returns them as a JSON list of block-hashes
func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]core.BadBlockArgs, error) { func (api *PrivateDebugAPI) GetBadBlocks(ctx context.Context) ([]*BadBlockArgs, error) {
return api.eth.BlockChain().BadBlocks() blocks := api.eth.BlockChain().BadBlocks()
results := make([]*BadBlockArgs, len(blocks))
var err error
for i, block := range blocks {
results[i] = &BadBlockArgs{
Hash: block.Hash(),
}
if rlpBytes, err := rlp.EncodeToBytes(block); err != nil {
results[i].RLP = err.Error() // Hacky, but hey, it works
} else {
results[i].RLP = fmt.Sprintf("0x%x", rlpBytes)
}
if results[i].Block, err = ethapi.RPCMarshalBlock(block, true, true); err != nil {
results[i].Block = map[string]interface{}{"error": err.Error()}
}
}
return results, nil
} }
// StorageRangeResult is the result of a debug_storageRangeAt API call. // StorageRangeResult is the result of a debug_storageRangeAt API call.

View file

@ -340,6 +340,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
return errResp(ErrDecode, "%v: %v", msg, err) return errResp(ErrDecode, "%v: %v", msg, err)
} }
hashMode := query.Origin.Hash != (common.Hash{}) hashMode := query.Origin.Hash != (common.Hash{})
first := true
maxNonCanonical := uint64(100)
// Gather headers until the fetch or network limits is reached // Gather headers until the fetch or network limits is reached
var ( var (
@ -351,31 +353,36 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Retrieve the next header satisfying the query // Retrieve the next header satisfying the query
var origin *types.Header var origin *types.Header
if hashMode { if hashMode {
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) if first {
first = false
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
if origin != nil {
query.Origin.Number = origin.Number.Uint64()
}
} else {
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
}
} else { } else {
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
} }
if origin == nil { if origin == nil {
break break
} }
number := origin.Number.Uint64()
headers = append(headers, origin) headers = append(headers, origin)
bytes += estHeaderRlpSize bytes += estHeaderRlpSize
// Advance to the next header of the query // Advance to the next header of the query
switch { switch {
case query.Origin.Hash != (common.Hash{}) && query.Reverse: case hashMode && query.Reverse:
// Hash based traversal towards the genesis block // Hash based traversal towards the genesis block
for i := 0; i < int(query.Skip)+1; i++ { ancestor := query.Skip + 1
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil { if ancestor == 0 {
query.Origin.Hash = header.ParentHash unknown = true
number-- } else {
} else { query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
unknown = true unknown = (query.Origin.Hash == common.Hash{})
break
}
} }
case query.Origin.Hash != (common.Hash{}) && !query.Reverse: case hashMode && !query.Reverse:
// Hash based traversal towards the leaf block // Hash based traversal towards the leaf block
var ( var (
current = origin.Number.Uint64() current = origin.Number.Uint64()
@ -387,8 +394,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
unknown = true unknown = true
} else { } else {
if header := pm.blockchain.GetHeaderByNumber(next); header != nil { if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { nextHash := header.Hash()
query.Origin.Hash = header.Hash() expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
if expOldHash == query.Origin.Hash {
query.Origin.Hash, query.Origin.Number = nextHash, next
} else { } else {
unknown = true unknown = true
} }

View file

@ -141,7 +141,9 @@ func (ec *Client) getBlock(ctx context.Context, method string, args ...interface
// Fill the sender cache of transactions in the block. // Fill the sender cache of transactions in the block.
txs := make([]*types.Transaction, len(body.Transactions)) txs := make([]*types.Transaction, len(body.Transactions))
for i, tx := range body.Transactions { for i, tx := range body.Transactions {
setSenderFromServer(tx.tx, tx.From, body.Hash) if tx.From != nil {
setSenderFromServer(tx.tx, *tx.From, body.Hash)
}
txs[i] = tx.tx txs[i] = tx.tx
} }
return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil return types.NewBlockWithHeader(head).WithBody(txs, uncles), nil
@ -174,9 +176,9 @@ type rpcTransaction struct {
} }
type txExtraInfo struct { type txExtraInfo struct {
BlockNumber *string BlockNumber *string `json:"blockNumber,omitempty"`
BlockHash common.Hash BlockHash *common.Hash `json:"blockHash,omitempty"`
From common.Address From *common.Address `json:"from,omitempty"`
} }
func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error { func (tx *rpcTransaction) UnmarshalJSON(msg []byte) error {
@ -197,7 +199,9 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (tx *
} else if _, r, _ := json.tx.RawSignatureValues(); r == nil { } else if _, r, _ := json.tx.RawSignatureValues(); r == nil {
return nil, false, fmt.Errorf("server returned transaction without signature") return nil, false, fmt.Errorf("server returned transaction without signature")
} }
setSenderFromServer(json.tx, json.From, json.BlockHash) if json.From != nil && json.BlockHash != nil {
setSenderFromServer(json.tx, *json.From, *json.BlockHash)
}
return json.tx, json.BlockNumber == nil, nil return json.tx, json.BlockNumber == nil, nil
} }
@ -244,7 +248,9 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
return nil, fmt.Errorf("server returned transaction without signature") return nil, fmt.Errorf("server returned transaction without signature")
} }
} }
setSenderFromServer(json.tx, json.From, json.BlockHash) if json.From != nil && json.BlockHash != nil {
setSenderFromServer(json.tx, *json.From, *json.BlockHash)
}
return json.tx, err return json.tx, err
} }

View file

@ -141,6 +141,7 @@ func (db *LDBDatabase) Close() {
if err := <-errc; err != nil { if err := <-errc; err != nil {
db.log.Error("Metrics collection failed", "err", err) db.log.Error("Metrics collection failed", "err", err)
} }
db.quitChan = nil
} }
err := db.db.Close() err := db.db.Close()
if err == nil { if err == nil {
@ -189,7 +190,7 @@ func (db *LDBDatabase) Meter(prefix string) {
// 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000 // 3 | 570 | 1113.18458 | 0.00000 | 0.00000 | 0.00000
// //
// This is how the write delay look like (currently): // This is how the write delay look like (currently):
// DelayN:5 Delay:406.604657ms // DelayN:5 Delay:406.604657ms Paused: false
// //
// This is how the iostats look like (currently): // This is how the iostats look like (currently):
// Read(MB):3895.04860 Write(MB):3654.64712 // Read(MB):3895.04860 Write(MB):3654.64712
@ -210,13 +211,19 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
lastWritePaused time.Time lastWritePaused time.Time
) )
var (
errc chan error
merr error
)
// Iterate ad infinitum and collect the stats // Iterate ad infinitum and collect the stats
for i := 1; ; i++ { for i := 1; errc == nil && merr == nil; i++ {
// Retrieve the database stats // Retrieve the database stats
stats, err := db.db.GetProperty("leveldb.stats") stats, err := db.db.GetProperty("leveldb.stats")
if err != nil { if err != nil {
db.log.Error("Failed to read database stats", "err", err) db.log.Error("Failed to read database stats", "err", err)
return merr = err
continue
} }
// Find the compaction table, skip the header // Find the compaction table, skip the header
lines := strings.Split(stats, "\n") lines := strings.Split(stats, "\n")
@ -225,7 +232,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
} }
if len(lines) <= 3 { if len(lines) <= 3 {
db.log.Error("Compaction table not found") db.log.Error("Compaction table not found")
return merr = errors.New("compaction table not found")
continue
} }
lines = lines[3:] lines = lines[3:]
@ -242,7 +250,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64) value, err := strconv.ParseFloat(strings.TrimSpace(counter), 64)
if err != nil { if err != nil {
db.log.Error("Compaction entry parsing failed", "err", err) db.log.Error("Compaction entry parsing failed", "err", err)
return merr = err
continue
} }
compactions[i%2][idx] += value compactions[i%2][idx] += value
} }
@ -262,7 +271,8 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
writedelay, err := db.db.GetProperty("leveldb.writedelay") writedelay, err := db.db.GetProperty("leveldb.writedelay")
if err != nil { if err != nil {
db.log.Error("Failed to read database write delay statistic", "err", err) db.log.Error("Failed to read database write delay statistic", "err", err)
return merr = err
continue
} }
var ( var (
delayN int64 delayN int64
@ -272,12 +282,14 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
) )
if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil { if n, err := fmt.Sscanf(writedelay, "DelayN:%d Delay:%s Paused:%t", &delayN, &delayDuration, &paused); n != 3 || err != nil {
db.log.Error("Write delay statistic not found") db.log.Error("Write delay statistic not found")
return merr = err
continue
} }
duration, err = time.ParseDuration(delayDuration) duration, err = time.ParseDuration(delayDuration)
if err != nil { if err != nil {
db.log.Error("Failed to parse delay duration", "err", err) db.log.Error("Failed to parse delay duration", "err", err)
return merr = err
continue
} }
if db.writeDelayNMeter != nil { if db.writeDelayNMeter != nil {
db.writeDelayNMeter.Mark(delayN - delaystats[0]) db.writeDelayNMeter.Mark(delayN - delaystats[0])
@ -317,53 +329,47 @@ func (db *LDBDatabase) meter(refresh time.Duration) {
ioStats, err := db.db.GetProperty("leveldb.iostats") ioStats, err := db.db.GetProperty("leveldb.iostats")
if err != nil { if err != nil {
db.log.Error("Failed to read database iostats", "err", err) db.log.Error("Failed to read database iostats", "err", err)
return merr = err
continue
} }
var nRead, nWrite float64
parts := strings.Split(ioStats, " ") parts := strings.Split(ioStats, " ")
if len(parts) < 2 { if len(parts) < 2 {
db.log.Error("Bad syntax of ioStats", "ioStats", ioStats) db.log.Error("Bad syntax of ioStats", "ioStats", ioStats)
return merr = fmt.Errorf("bad syntax of ioStats %s", ioStats)
continue
} }
r := strings.Split(parts[0], ":") if n, err := fmt.Sscanf(parts[0], "Read(MB):%f", &nRead); n != 1 || err != nil {
if len(r) < 2 {
db.log.Error("Bad syntax of read entry", "entry", parts[0]) db.log.Error("Bad syntax of read entry", "entry", parts[0])
return merr = err
continue
} }
read, err := strconv.ParseFloat(r[1], 64) if n, err := fmt.Sscanf(parts[1], "Write(MB):%f", &nWrite); n != 1 || err != nil {
if err != nil {
db.log.Error("Read entry parsing failed", "err", err)
return
}
w := strings.Split(parts[1], ":")
if len(w) < 2 {
db.log.Error("Bad syntax of write entry", "entry", parts[1]) db.log.Error("Bad syntax of write entry", "entry", parts[1])
return merr = err
} continue
write, err := strconv.ParseFloat(w[1], 64)
if err != nil {
db.log.Error("Write entry parsing failed", "err", err)
return
} }
if db.diskReadMeter != nil { if db.diskReadMeter != nil {
db.diskReadMeter.Mark(int64((read - iostats[0]) * 1024 * 1024)) db.diskReadMeter.Mark(int64((nRead - iostats[0]) * 1024 * 1024))
} }
if db.diskWriteMeter != nil { if db.diskWriteMeter != nil {
db.diskWriteMeter.Mark(int64((write - iostats[1]) * 1024 * 1024)) db.diskWriteMeter.Mark(int64((nWrite - iostats[1]) * 1024 * 1024))
} }
iostats[0] = read iostats[0], iostats[1] = nRead, nWrite
iostats[1] = write
// Sleep a bit, then repeat the stats collection // Sleep a bit, then repeat the stats collection
select { select {
case errc := <-db.quitChan: case errc = <-db.quitChan:
// Quit requesting, stop hammering the database // Quit requesting, stop hammering the database
errc <- nil
return
case <-time.After(refresh): case <-time.After(refresh):
// Timeout, gather a new set of stats // Timeout, gather a new set of stats
} }
} }
if errc == nil {
errc = <-db.quitChan
}
errc <- merr
} }
func (db *LDBDatabase) NewBatch() Batch { func (db *LDBDatabase) NewBatch() Batch {

View file

@ -62,8 +62,9 @@ func NewPublicEthereumAPI(b Backend) *PublicEthereumAPI {
} }
// GasPrice returns a suggestion for a gas price. // GasPrice returns a suggestion for a gas price.
func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*big.Int, error) { func (s *PublicEthereumAPI) GasPrice(ctx context.Context) (*hexutil.Big, error) {
return s.b.SuggestPrice(ctx) price, err := s.b.SuggestPrice(ctx)
return (*hexutil.Big)(price), err
} }
// ProtocolVersion returns the current Ethereum protocol version this node supports // ProtocolVersion returns the current Ethereum protocol version this node supports
@ -460,13 +461,11 @@ func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Byt
} }
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
rpk, err := crypto.Ecrecover(signHash(data), sig) rpk, err := crypto.SigToPub(signHash(data), sig)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
pubKey := crypto.ToECDSAPub(rpk) return crypto.PubkeyToAddress(*rpk), nil
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
return recoveredAddr, nil
} }
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated // SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
@ -487,21 +486,20 @@ func NewPublicBlockChainAPI(b Backend) *PublicBlockChainAPI {
} }
// BlockNumber returns the block number of the chain head. // BlockNumber returns the block number of the chain head.
func (s *PublicBlockChainAPI) BlockNumber() *big.Int { func (s *PublicBlockChainAPI) BlockNumber() hexutil.Uint64 {
header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available header, _ := s.b.HeaderByNumber(context.Background(), rpc.LatestBlockNumber) // latest header should always be available
return header.Number return hexutil.Uint64(header.Number.Uint64())
} }
// GetBalance returns the amount of wei for the given address in the state of the // GetBalance returns the amount of wei for the given address in the state of the
// given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta // given block number. The rpc.LatestBlockNumber and rpc.PendingBlockNumber meta
// block numbers are also allowed. // block numbers are also allowed.
func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*big.Int, error) { func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Address, blockNr rpc.BlockNumber) (*hexutil.Big, error) {
state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr) state, _, err := s.b.StateAndHeaderByNumber(ctx, blockNr)
if state == nil || err != nil { if state == nil || err != nil {
return nil, err return nil, err
} }
b := state.GetBalance(address) return (*hexutil.Big)(state.GetBalance(address)), state.Error()
return b, state.Error()
} }
// GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all // GetBlockByNumber returns the requested block. When blockNr is -1 the chain head is returned. When fullTx is true all
@ -792,10 +790,10 @@ func FormatLogs(logs []vm.StructLog) []StructLogRes {
return formatted return formatted
} }
// rpcOutputBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are // RPCMarshalBlock converts the given block to the RPC output which depends on fullTx. If inclTx is true transactions are
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes. // transaction hashes.
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { func RPCMarshalBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
head := b.Header() // copies the header once head := b.Header() // copies the header once
fields := map[string]interface{}{ fields := map[string]interface{}{
"number": (*hexutil.Big)(head.Number), "number": (*hexutil.Big)(head.Number),
@ -808,7 +806,6 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
"stateRoot": head.Root, "stateRoot": head.Root,
"miner": head.Coinbase, "miner": head.Coinbase,
"difficulty": (*hexutil.Big)(head.Difficulty), "difficulty": (*hexutil.Big)(head.Difficulty),
"totalDifficulty": (*hexutil.Big)(s.b.GetTd(b.Hash())),
"extraData": hexutil.Bytes(head.Extra), "extraData": hexutil.Bytes(head.Extra),
"size": hexutil.Uint64(b.Size()), "size": hexutil.Uint64(b.Size()),
"gasLimit": hexutil.Uint64(head.GasLimit), "gasLimit": hexutil.Uint64(head.GasLimit),
@ -822,17 +819,15 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
formatTx := func(tx *types.Transaction) (interface{}, error) { formatTx := func(tx *types.Transaction) (interface{}, error) {
return tx.Hash(), nil return tx.Hash(), nil
} }
if fullTx { if fullTx {
formatTx = func(tx *types.Transaction) (interface{}, error) { formatTx = func(tx *types.Transaction) (interface{}, error) {
return newRPCTransactionFromBlockHash(b, tx.Hash()), nil return newRPCTransactionFromBlockHash(b, tx.Hash()), nil
} }
} }
txs := b.Transactions() txs := b.Transactions()
transactions := make([]interface{}, len(txs)) transactions := make([]interface{}, len(txs))
var err error var err error
for i, tx := range b.Transactions() { for i, tx := range txs {
if transactions[i], err = formatTx(tx); err != nil { if transactions[i], err = formatTx(tx); err != nil {
return nil, err return nil, err
} }
@ -850,6 +845,17 @@ func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx
return fields, nil return fields, nil
} }
// rpcOutputBlock uses the generalized output filler, then adds the total difficulty field, which requires
// a `PublicBlockchainAPI`.
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
fields, err := RPCMarshalBlock(b, inclTx, fullTx)
if err != nil {
return nil, err
}
fields["totalDifficulty"] = (*hexutil.Big)(s.b.GetTd(b.Hash()))
return fields, err
}
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
type RPCTransaction struct { type RPCTransaction struct {
BlockHash common.Hash `json:"blockHash"` BlockHash common.Hash `json:"blockHash"`
@ -1293,14 +1299,19 @@ func (s *PublicTransactionPoolAPI) SignTransaction(ctx context.Context, args Sen
return &SignTransactionResult{data, tx}, nil return &SignTransactionResult{data, tx}, nil
} }
// PendingTransactions returns the transactions that are in the transaction pool and have a from address that is one of // PendingTransactions returns the transactions that are in the transaction pool
// the accounts this node manages. // and have a from address that is one of the accounts this node manages.
func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) { func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, error) {
pending, err := s.b.GetPoolTransactions() pending, err := s.b.GetPoolTransactions()
if err != nil { if err != nil {
return nil, err return nil, err
} }
accounts := make(map[common.Address]struct{})
for _, wallet := range s.b.AccountManager().Wallets() {
for _, account := range wallet.Accounts() {
accounts[account.Address] = struct{}{}
}
}
transactions := make([]*RPCTransaction, 0, len(pending)) transactions := make([]*RPCTransaction, 0, len(pending))
for _, tx := range pending { for _, tx := range pending {
var signer types.Signer = types.HomesteadSigner{} var signer types.Signer = types.HomesteadSigner{}
@ -1308,7 +1319,7 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() ([]*RPCTransaction, err
signer = types.NewEIP155Signer(tx.ChainId()) signer = types.NewEIP155Signer(tx.ChainId())
} }
from, _ := types.Sender(signer, tx) from, _ := types.Sender(signer, tx)
if _, err := s.b.AccountManager().Find(accounts.Account{Address: from}); err == nil { if _, exists := accounts[from]; exists {
transactions = append(transactions, newRPCPendingTransaction(tx)) transactions = append(transactions, newRPCPendingTransaction(tx))
} }
} }

View file

@ -127,7 +127,7 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
} }
leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay) leth.txPool = light.NewTxPool(leth.chainConfig, leth.blockchain, leth.relay)
if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, quitSync, &leth.wg); err != nil { if leth.protocolManager, err = NewProtocolManager(leth.chainConfig, true, ClientProtocolVersions, config.NetworkId, leth.eventMux, leth.engine, leth.peers, leth.blockchain, nil, chainDb, leth.odr, leth.relay, leth.serverPool, quitSync, &leth.wg); err != nil {
return nil, err return nil, err
} }
leth.ApiBackend = &LesApiBackend{leth, nil} leth.ApiBackend = &LesApiBackend{leth, nil}

View file

@ -83,7 +83,7 @@ type BlockChain interface {
InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error) InsertHeaderChain(chain []*types.Header, checkFreq int) (int, error)
Rollback(chain []common.Hash) Rollback(chain []common.Hash)
GetHeaderByNumber(number uint64) *types.Header GetHeaderByNumber(number uint64) *types.Header
GetBlockHashesFromHash(hash common.Hash, max uint64) []common.Hash GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64)
Genesis() *types.Block Genesis() *types.Block
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
} }
@ -129,7 +129,7 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable // NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network. // with the ethereum network.
func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protocolVersions []uint, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, quitSync chan struct{}, wg *sync.WaitGroup) (*ProtocolManager, error) { func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protocolVersions []uint, networkId uint64, mux *event.TypeMux, engine consensus.Engine, peers *peerSet, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay, serverPool *serverPool, quitSync chan struct{}, wg *sync.WaitGroup) (*ProtocolManager, error) {
// Create the protocol manager with the base fields // Create the protocol manager with the base fields
manager := &ProtocolManager{ manager := &ProtocolManager{
lightSync: lightSync, lightSync: lightSync,
@ -141,6 +141,7 @@ func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, protoco
networkId: networkId, networkId: networkId,
txpool: txpool, txpool: txpool,
txrelay: txrelay, txrelay: txrelay,
serverPool: serverPool,
peers: peers, peers: peers,
newPeerCh: make(chan *peer), newPeerCh: make(chan *peer),
quitSync: quitSync, quitSync: quitSync,
@ -418,6 +419,8 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
} }
hashMode := query.Origin.Hash != (common.Hash{}) hashMode := query.Origin.Hash != (common.Hash{})
first := true
maxNonCanonical := uint64(100)
// Gather headers until the fetch or network limits is reached // Gather headers until the fetch or network limits is reached
var ( var (
@ -429,14 +432,21 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
// Retrieve the next header satisfying the query // Retrieve the next header satisfying the query
var origin *types.Header var origin *types.Header
if hashMode { if hashMode {
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash) if first {
first = false
origin = pm.blockchain.GetHeaderByHash(query.Origin.Hash)
if origin != nil {
query.Origin.Number = origin.Number.Uint64()
}
} else {
origin = pm.blockchain.GetHeader(query.Origin.Hash, query.Origin.Number)
}
} else { } else {
origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number) origin = pm.blockchain.GetHeaderByNumber(query.Origin.Number)
} }
if origin == nil { if origin == nil {
break break
} }
number := origin.Number.Uint64()
headers = append(headers, origin) headers = append(headers, origin)
bytes += estHeaderRlpSize bytes += estHeaderRlpSize
@ -444,14 +454,12 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
switch { switch {
case hashMode && query.Reverse: case hashMode && query.Reverse:
// Hash based traversal towards the genesis block // Hash based traversal towards the genesis block
for i := 0; i < int(query.Skip)+1; i++ { ancestor := query.Skip + 1
if header := pm.blockchain.GetHeader(query.Origin.Hash, number); header != nil { if ancestor == 0 {
query.Origin.Hash = header.ParentHash unknown = true
number-- } else {
} else { query.Origin.Hash, query.Origin.Number = pm.blockchain.GetAncestor(query.Origin.Hash, query.Origin.Number, ancestor, &maxNonCanonical)
unknown = true unknown = (query.Origin.Hash == common.Hash{})
break
}
} }
case hashMode && !query.Reverse: case hashMode && !query.Reverse:
// Hash based traversal towards the leaf block // Hash based traversal towards the leaf block
@ -465,8 +473,10 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
unknown = true unknown = true
} else { } else {
if header := pm.blockchain.GetHeaderByNumber(next); header != nil { if header := pm.blockchain.GetHeaderByNumber(next); header != nil {
if pm.blockchain.GetBlockHashesFromHash(header.Hash(), query.Skip+1)[query.Skip] == query.Origin.Hash { nextHash := header.Hash()
query.Origin.Hash = header.Hash() expOldHash, _ := pm.blockchain.GetAncestor(nextHash, next, query.Skip+1, &maxNonCanonical)
if expOldHash == query.Origin.Hash {
query.Origin.Hash, query.Origin.Number = nextHash, next
} else { } else {
unknown = true unknown = true
} }

View file

@ -178,7 +178,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
} else { } else {
protocolVersions = ServerProtocolVersions protocolVersions = ServerProtocolVersions
} }
pm, err := NewProtocolManager(gspec.Config, lightSync, protocolVersions, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, make(chan struct{}), new(sync.WaitGroup)) pm, err := NewProtocolManager(gspec.Config, lightSync, protocolVersions, NetworkId, evmux, engine, peers, chain, nil, db, odr, nil, nil, make(chan struct{}), new(sync.WaitGroup))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -69,9 +69,9 @@ type sentReq struct {
lock sync.RWMutex // protect access to sentTo map lock sync.RWMutex // protect access to sentTo map
sentTo map[distPeer]sentReqToPeer sentTo map[distPeer]sentReqToPeer
reqQueued bool // a request has been queued but not sent lastReqQueued bool // last request has been queued but not sent
reqSent bool // a request has been sent but not timed out lastReqSentTo distPeer // if not nil then last request has been sent to given peer but not timed out
reqSrtoCount int // number of requests that reached soft (but not hard) timeout reqSrtoCount int // number of requests that reached soft (but not hard) timeout
} }
// sentReqToPeer notifies the request-from-peer goroutine (tryRequest) about a response // sentReqToPeer notifies the request-from-peer goroutine (tryRequest) about a response
@ -180,7 +180,7 @@ type reqStateFn func() reqStateFn
// retrieveLoop is the retrieval state machine event loop // retrieveLoop is the retrieval state machine event loop
func (r *sentReq) retrieveLoop() { func (r *sentReq) retrieveLoop() {
go r.tryRequest() go r.tryRequest()
r.reqQueued = true r.lastReqQueued = true
state := r.stateRequesting state := r.stateRequesting
for state != nil { for state != nil {
@ -214,7 +214,7 @@ func (r *sentReq) stateRequesting() reqStateFn {
case rpSoftTimeout: case rpSoftTimeout:
// last request timed out, try asking a new peer // last request timed out, try asking a new peer
go r.tryRequest() go r.tryRequest()
r.reqQueued = true r.lastReqQueued = true
return r.stateRequesting return r.stateRequesting
case rpDeliveredValid: case rpDeliveredValid:
r.stop(nil) r.stop(nil)
@ -233,7 +233,7 @@ func (r *sentReq) stateNoMorePeers() reqStateFn {
select { select {
case <-time.After(retryQueue): case <-time.After(retryQueue):
go r.tryRequest() go r.tryRequest()
r.reqQueued = true r.lastReqQueued = true
return r.stateRequesting return r.stateRequesting
case ev := <-r.eventsCh: case ev := <-r.eventsCh:
r.update(ev) r.update(ev)
@ -260,22 +260,26 @@ func (r *sentReq) stateStopped() reqStateFn {
func (r *sentReq) update(ev reqPeerEvent) { func (r *sentReq) update(ev reqPeerEvent) {
switch ev.event { switch ev.event {
case rpSent: case rpSent:
r.reqQueued = false r.lastReqQueued = false
if ev.peer != nil { r.lastReqSentTo = ev.peer
r.reqSent = true
}
case rpSoftTimeout: case rpSoftTimeout:
r.reqSent = false r.lastReqSentTo = nil
r.reqSrtoCount++ r.reqSrtoCount++
case rpHardTimeout, rpDeliveredValid, rpDeliveredInvalid: case rpHardTimeout:
r.reqSrtoCount-- r.reqSrtoCount--
case rpDeliveredValid, rpDeliveredInvalid:
if ev.peer == r.lastReqSentTo {
r.lastReqSentTo = nil
} else {
r.reqSrtoCount--
}
} }
} }
// waiting returns true if the retrieval mechanism is waiting for an answer from // waiting returns true if the retrieval mechanism is waiting for an answer from
// any peer // any peer
func (r *sentReq) waiting() bool { func (r *sentReq) waiting() bool {
return r.reqQueued || r.reqSent || r.reqSrtoCount > 0 return r.lastReqQueued || r.lastReqSentTo != nil || r.reqSrtoCount > 0
} }
// tryRequest tries to send the request to a new peer and waits for it to either // tryRequest tries to send the request to a new peer and waits for it to either

View file

@ -52,7 +52,7 @@ type LesServer struct {
func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) { func NewLesServer(eth *eth.Ethereum, config *eth.Config) (*LesServer, error) {
quitSync := make(chan struct{}) quitSync := make(chan struct{})
pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, quitSync, new(sync.WaitGroup)) pm, err := NewProtocolManager(eth.BlockChain().Config(), false, ServerProtocolVersions, config.NetworkId, eth.EventMux(), eth.Engine(), newPeerSet(), eth.BlockChain(), eth.TxPool(), eth.ChainDb(), nil, nil, nil, quitSync, new(sync.WaitGroup))
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -433,6 +433,18 @@ func (self *LightChain) GetBlockHashesFromHash(hash common.Hash, max uint64) []c
return self.hc.GetBlockHashesFromHash(hash, max) return self.hc.GetBlockHashesFromHash(hash, max)
} }
// GetAncestor retrieves the Nth ancestor of a given block. It assumes that either the given block or
// a close ancestor of it is canonical. maxNonCanonical points to a downwards counter limiting the
// number of blocks to be individually checked before we reach the canonical chain.
//
// Note: ancestor == 0 returns the same block, 1 returns its parent and so on.
func (bc *LightChain) GetAncestor(hash common.Hash, number, ancestor uint64, maxNonCanonical *uint64) (common.Hash, uint64) {
bc.chainmu.Lock()
defer bc.chainmu.Unlock()
return bc.hc.GetAncestor(hash, number, ancestor, maxNonCanonical)
}
// GetHeaderByNumber retrieves a block header from the database by number, // GetHeaderByNumber retrieves a block header from the database by number,
// caching it (associated with its hash) if found. // caching it (associated with its hash) if found.
func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header { func (self *LightChain) GetHeaderByNumber(number uint64) *types.Header {

View file

@ -59,18 +59,18 @@ type trustedCheckpoint struct {
var ( var (
mainnetCheckpoint = trustedCheckpoint{ mainnetCheckpoint = trustedCheckpoint{
name: "mainnet", name: "mainnet",
sectionIdx: 170, sectionIdx: 174,
sectionHead: common.HexToHash("3bb2c28bcce463d57968f14f56cdb3fbf35349ab7a701f44c1afb57349c9a356"), sectionHead: common.HexToHash("a3ef48cd8f1c3a08419f0237fc7763491fe89497b3144b17adf87c1c43664613"),
chtRoot: common.HexToHash("d92b6d0853455f8439086292338e87f69781921680dd7aa072fb71547b87415e"), chtRoot: common.HexToHash("dcbeed9f4dea1b3cb75601bb27c51b9960c28e5850275402ac49a150a667296e"),
bloomTrieRoot: common.HexToHash("e4e8250a2fefddead7ae42daecd848cbf9b66d748a8270f8bbd4370b764bb9e9"), bloomTrieRoot: common.HexToHash("6b7497a4a03e33870a2383cb6f5e70570f12b1bf5699063baf8c71d02ca90b02"),
} }
ropstenCheckpoint = trustedCheckpoint{ ropstenCheckpoint = trustedCheckpoint{
name: "ropsten", name: "ropsten",
sectionIdx: 97, sectionIdx: 102,
sectionHead: common.HexToHash("719448c67c01eb5b9f27833a36a4e34612f66801316d7ff37daf9e77fb4cd095"), sectionHead: common.HexToHash("9017ab08465cb2b2dee035ee5b817bbd7fa28e2c8d2cd903e0aed1cccb249e89"),
chtRoot: common.HexToHash("a7857afc15930ca6e583b6c3d563a025144011655843d52d28e2fdaadd417bea"), chtRoot: common.HexToHash("f61c10a7a787a5ef15f0ae1ae6c13c64331e57e79d0466d2bd9b0c06833fe956"),
bloomTrieRoot: common.HexToHash("9c71d4b50cbec86dfeaa8e08992de8a4667b81d13c54d6522b17ce2fc5d36416"), bloomTrieRoot: common.HexToHash("69f2ad19aa46d5213a90137b3d2c9bff8a7c9483f7170f0125096ff450c9a873"),
} }
) )

View file

@ -68,17 +68,20 @@ func CollectProcessMetrics(refresh time.Duration) {
} }
// Iterate loading the different stats and updating the meters // Iterate loading the different stats and updating the meters
for i := 1; ; i++ { for i := 1; ; i++ {
runtime.ReadMemStats(memstats[i%2]) location1 := i % 2
memAllocs.Mark(int64(memstats[i%2].Mallocs - memstats[(i-1)%2].Mallocs)) location2 := (i - 1) % 2
memFrees.Mark(int64(memstats[i%2].Frees - memstats[(i-1)%2].Frees))
memInuse.Mark(int64(memstats[i%2].Alloc - memstats[(i-1)%2].Alloc))
memPauses.Mark(int64(memstats[i%2].PauseTotalNs - memstats[(i-1)%2].PauseTotalNs))
if ReadDiskStats(diskstats[i%2]) == nil { runtime.ReadMemStats(memstats[location1])
diskReads.Mark(diskstats[i%2].ReadCount - diskstats[(i-1)%2].ReadCount) memAllocs.Mark(int64(memstats[location1].Mallocs - memstats[location2].Mallocs))
diskReadBytes.Mark(diskstats[i%2].ReadBytes - diskstats[(i-1)%2].ReadBytes) memFrees.Mark(int64(memstats[location1].Frees - memstats[location2].Frees))
diskWrites.Mark(diskstats[i%2].WriteCount - diskstats[(i-1)%2].WriteCount) memInuse.Mark(int64(memstats[location1].Alloc - memstats[location2].Alloc))
diskWriteBytes.Mark(diskstats[i%2].WriteBytes - diskstats[(i-1)%2].WriteBytes) memPauses.Mark(int64(memstats[location1].PauseTotalNs - memstats[location2].PauseTotalNs))
if ReadDiskStats(diskstats[location1]) == nil {
diskReads.Mark(diskstats[location1].ReadCount - diskstats[location2].ReadCount)
diskReadBytes.Mark(diskstats[location1].ReadBytes - diskstats[location2].ReadBytes)
diskWrites.Mark(diskstats[location1].WriteCount - diskstats[location2].WriteCount)
diskWriteBytes.Mark(diskstats[location1].WriteBytes - diskstats[location2].WriteBytes)
} }
time.Sleep(refresh) time.Sleep(refresh)
} }

View file

@ -58,7 +58,11 @@ type NilResettingTimer struct {
func (NilResettingTimer) Values() []int64 { return nil } func (NilResettingTimer) Values() []int64 { return nil }
// Snapshot is a no-op. // Snapshot is a no-op.
func (NilResettingTimer) Snapshot() ResettingTimer { return NilResettingTimer{} } func (NilResettingTimer) Snapshot() ResettingTimer {
return &ResettingTimerSnapshot{
values: []int64{},
}
}
// Time is a no-op. // Time is a no-op.
func (NilResettingTimer) Time(func()) {} func (NilResettingTimer) Time(func()) {}

View file

@ -528,9 +528,9 @@ func importPublicKey(pubKey []byte) (*ecies.PublicKey, error) {
return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey)) return nil, fmt.Errorf("invalid public key length %v (expect 64/65)", len(pubKey))
} }
// TODO: fewer pointless conversions // TODO: fewer pointless conversions
pub := crypto.ToECDSAPub(pubKey65) pub, err := crypto.UnmarshalPubkey(pubKey65)
if pub.X == nil { if err != nil {
return nil, fmt.Errorf("invalid public key") return nil, err
} }
return ecies.ImportECDSAPublic(pub), nil return ecies.ImportECDSAPublic(pub), nil
} }

View file

@ -23,7 +23,7 @@ import (
const ( const (
VersionMajor = 1 // Major version component of the current release VersionMajor = 1 // Major version component of the current release
VersionMinor = 8 // Minor version component of the current release VersionMinor = 8 // Minor version component of the current release
VersionPatch = 11 // Patch version component of the current release VersionPatch = 12 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string VersionMeta = "unstable" // Version metadata to append to the version string
) )

View file

@ -320,9 +320,6 @@ func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]
// CreateResponse will create a JSON-RPC success response with the given id and reply as result. // CreateResponse will create a JSON-RPC success response with the given id and reply as result.
func (c *jsonCodec) CreateResponse(id interface{}, reply interface{}) interface{} { func (c *jsonCodec) CreateResponse(id interface{}, reply interface{}) interface{} {
if isHexNum(reflect.TypeOf(reply)) {
return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: fmt.Sprintf(`%#x`, reply)}
}
return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: reply} return &jsonSuccessResponse{Version: jsonrpcVersion, Id: id, Result: reply}
} }
@ -340,11 +337,6 @@ func (c *jsonCodec) CreateErrorResponseWithInfo(id interface{}, err Error, info
// CreateNotification will create a JSON-RPC notification with the given subscription id and event as params. // CreateNotification will create a JSON-RPC notification with the given subscription id and event as params.
func (c *jsonCodec) CreateNotification(subid, namespace string, event interface{}) interface{} { func (c *jsonCodec) CreateNotification(subid, namespace string, event interface{}) interface{} {
if isHexNum(reflect.TypeOf(event)) {
return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix,
Params: jsonSubscription{Subscription: subid, Result: fmt.Sprintf(`%#x`, event)}}
}
return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix, return &jsonNotification{Version: jsonrpcVersion, Method: namespace + notificationMethodSuffix,
Params: jsonSubscription{Subscription: subid, Result: event}} Params: jsonSubscription{Subscription: subid, Result: event}}
} }

View file

@ -145,7 +145,7 @@ func (s *Server) serveRequest(ctx context.Context, codec ServerCodec, singleShot
defer cancel() defer cancel()
// if the codec supports notification include a notifier that callbacks can use // if the codec supports notification include a notifier that callbacks can use
// to send notification to clients. It is thight to the codec/connection. If the // to send notification to clients. It is tied to the codec/connection. If the
// connection is closed the notifier will stop and cancels all active subscriptions. // connection is closed the notifier will stop and cancels all active subscriptions.
if options&OptionSubscriptions == OptionSubscriptions { if options&OptionSubscriptions == OptionSubscriptions {
ctx = context.WithValue(ctx, notifierKey{}, newNotifier(codec)) ctx = context.WithValue(ctx, notifierKey{}, newNotifier(codec))
@ -313,7 +313,6 @@ func (s *Server) handle(ctx context.Context, codec ServerCodec, req *serverReque
if len(reply) == 0 { if len(reply) == 0 {
return codec.CreateResponse(req.id, nil), nil return codec.CreateResponse(req.id, nil), nil
} }
if req.callb.errPos >= 0 { // test if method returned an error if req.callb.errPos >= 0 { // test if method returned an error
if !reply[req.callb.errPos].IsNil() { if !reply[req.callb.errPos].IsNil() {
e := reply[req.callb.errPos].Interface().(error) e := reply[req.callb.errPos].Interface().(error)

View file

@ -22,7 +22,6 @@ import (
crand "crypto/rand" crand "crypto/rand"
"encoding/binary" "encoding/binary"
"encoding/hex" "encoding/hex"
"math/big"
"math/rand" "math/rand"
"reflect" "reflect"
"strings" "strings"
@ -105,20 +104,6 @@ func formatName(name string) string {
return string(ret) return string(ret)
} }
var bigIntType = reflect.TypeOf((*big.Int)(nil)).Elem()
// Indication if this type should be serialized in hex
func isHexNum(t reflect.Type) bool {
if t == nil {
return false
}
for t.Kind() == reflect.Ptr {
t = t.Elem()
}
return t == bigIntType
}
// suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria // suitableCallbacks iterates over the methods of the given type. It will determine if a method satisfies the criteria
// for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server // for a RPC callback or a subscription callback and adds it to the collection of callbacks or subscriptions. See server
// documentation for a summary of these criteria. // documentation for a summary of these criteria.

View file

@ -432,13 +432,11 @@ func (api *SignerAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (c
} }
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1 sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
hash, _ := SignHash(data) hash, _ := SignHash(data)
rpk, err := crypto.Ecrecover(hash, sig) rpk, err := crypto.SigToPub(hash, sig)
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
pubKey := crypto.ToECDSAPub(rpk) return crypto.PubkeyToAddress(*rpk), nil
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
return recoveredAddr, nil
} }
// SignHash is a helper function that calculates a hash for the given message that can be // SignHash is a helper function that calculates a hash for the given message that can be

View file

@ -19,6 +19,7 @@ package swap
import ( import (
"context" "context"
"crypto/ecdsa" "crypto/ecdsa"
"errors"
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
@ -134,6 +135,11 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
out *chequebook.Outbox out *chequebook.Outbox
) )
remotekey, err := crypto.UnmarshalPubkey(common.FromHex(remote.PublicKey))
if err != nil {
return nil, errors.New("invalid remote public key")
}
// check if remote chequebook is valid // check if remote chequebook is valid
// insolvent chequebooks suicide so will signal as invalid // insolvent chequebooks suicide so will signal as invalid
// TODO: monitoring a chequebooks events // TODO: monitoring a chequebooks events
@ -142,7 +148,7 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)) log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
} else { } else {
// remote contract valid, create inbox // remote contract valid, create inbox
in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, crypto.ToECDSAPub(common.FromHex(remote.PublicKey)), backend) in, err = chequebook.NewInbox(local.privateKey, remote.Contract, local.Beneficiary, remotekey, backend)
if err != nil { if err != nil {
log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err)) log.Warn(fmt.Sprintf("unable to set up inbox for chequebook contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
} }

View file

@ -297,7 +297,7 @@ func (db *Database) Cap(limit common.StorageSize) error {
// db.nodesSize only contains the useful data in the cache, but when reporting // db.nodesSize only contains the useful data in the cache, but when reporting
// the total memory consumption, the maintenance metadata is also needed to be // the total memory consumption, the maintenance metadata is also needed to be
// counted. For every useful node, we track 2 extra hashes as the flushlist. // counted. For every useful node, we track 2 extra hashes as the flushlist.
size := db.nodesSize + common.StorageSize(len(db.nodes)*2*common.HashLength) size := db.nodesSize + common.StorageSize((len(db.nodes)-1)*2*common.HashLength)
// If the preimage cache got large enough, push to disk. If it's still small // If the preimage cache got large enough, push to disk. If it's still small
// leave for later to deduplicate writes. // leave for later to deduplicate writes.
@ -512,6 +512,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize) {
// db.nodesSize only contains the useful data in the cache, but when reporting // db.nodesSize only contains the useful data in the cache, but when reporting
// the total memory consumption, the maintenance metadata is also needed to be // the total memory consumption, the maintenance metadata is also needed to be
// counted. For every useful node, we track 2 extra hashes as the flushlist. // counted. For every useful node, we track 2 extra hashes as the flushlist.
var flushlistSize = common.StorageSize(len(db.nodes) * 2 * common.HashLength) var flushlistSize = common.StorageSize((len(db.nodes) - 1) * 2 * common.HashLength)
return db.nodesSize + flushlistSize, db.preimagesSize return db.nodesSize + flushlistSize, db.preimagesSize
} }

View file

@ -252,8 +252,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
// Set asymmetric key that is used to encrypt the message // Set asymmetric key that is used to encrypt the message
if pubKeyGiven { if pubKeyGiven {
params.Dst = crypto.ToECDSAPub(req.PublicKey) if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
if !ValidatePublicKey(params.Dst) {
return false, ErrInvalidPublicKey return false, ErrInvalidPublicKey
} }
} }
@ -329,8 +328,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
} }
if len(crit.Sig) > 0 { if len(crit.Sig) > 0 {
filter.Src = crypto.ToECDSAPub(crit.Sig) if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
if !ValidatePublicKey(filter.Src) {
return nil, ErrInvalidSigningPubKey return nil, ErrInvalidSigningPubKey
} }
} }
@ -513,8 +511,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
} }
if len(req.Sig) > 0 { if len(req.Sig) > 0 {
src = crypto.ToECDSAPub(req.Sig) if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
if !ValidatePublicKey(src) {
return "", ErrInvalidSigningPubKey return "", ErrInvalidSigningPubKey
} }
} }

View file

@ -272,8 +272,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (hexutil.
// Set asymmetric key that is used to encrypt the message // Set asymmetric key that is used to encrypt the message
if pubKeyGiven { if pubKeyGiven {
params.Dst = crypto.ToECDSAPub(req.PublicKey) if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
if !ValidatePublicKey(params.Dst) {
return nil, ErrInvalidPublicKey return nil, ErrInvalidPublicKey
} }
} }
@ -360,8 +359,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
} }
if len(crit.Sig) > 0 { if len(crit.Sig) > 0 {
filter.Src = crypto.ToECDSAPub(crit.Sig) if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
if !ValidatePublicKey(filter.Src) {
return nil, ErrInvalidSigningPubKey return nil, ErrInvalidSigningPubKey
} }
} }
@ -544,8 +542,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
} }
if len(req.Sig) > 0 { if len(req.Sig) > 0 {
src = crypto.ToECDSAPub(req.Sig) if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
if !ValidatePublicKey(src) {
return "", ErrInvalidSigningPubKey return "", ErrInvalidSigningPubKey
} }
} }