mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
core: types: less allocations when hashing and tx handling (#21265)
This commit is contained in:
parent
1776bf1313
commit
48f9bbed50
17 changed files with 305 additions and 114 deletions
|
|
@ -18,12 +18,14 @@
|
|||
package accounts
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
ethereum "github.com/XinFinOrg/XDPoSChain"
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/event"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// Account represents an Ethereum account located at a specific location defined
|
||||
|
|
@ -148,6 +150,34 @@ type Backend interface {
|
|||
Subscribe(sink chan<- WalletEvent) event.Subscription
|
||||
}
|
||||
|
||||
// TextHash is a helper function that calculates a hash for the given message that can be
|
||||
// safely used to calculate a signature from.
|
||||
//
|
||||
// The hash is calulcated as
|
||||
//
|
||||
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
||||
//
|
||||
// This gives context to the signed message and prevents signing of transactions.
|
||||
func TextHash(data []byte) []byte {
|
||||
hash, _ := TextAndHash(data)
|
||||
return hash
|
||||
}
|
||||
|
||||
// TextAndHash is a helper function that calculates a hash for the given message that can be
|
||||
// safely used to calculate a signature from.
|
||||
//
|
||||
// The hash is calulcated as
|
||||
//
|
||||
// keccak256("\x19Ethereum Signed Message:\n"${message length}${message}).
|
||||
//
|
||||
// This gives context to the signed message and prevents signing of transactions.
|
||||
func TextAndHash(data []byte) ([]byte, string) {
|
||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len(data), string(data))
|
||||
hasher := sha3.NewLegacyKeccak256()
|
||||
hasher.Write([]byte(msg))
|
||||
return hasher.Sum(nil), msg
|
||||
}
|
||||
|
||||
// WalletEventType represents the different event types that can be fired by
|
||||
// the wallet subscription subsystem.
|
||||
type WalletEventType int
|
||||
|
|
|
|||
|
|
@ -139,8 +139,8 @@ func processArgs() {
|
|||
}
|
||||
|
||||
if *asymmetricMode && len(*argPub) > 0 {
|
||||
pub = crypto.ToECDSAPub(common.FromHex(*argPub))
|
||||
if !isKeyValid(pub) {
|
||||
var err error
|
||||
if pub, err = crypto.UnmarshalPubkey(common.FromHex(*argPub)); err != nil {
|
||||
utils.Fatalf("invalid public key")
|
||||
}
|
||||
}
|
||||
|
|
@ -337,9 +337,8 @@ func configureNode() {
|
|||
if b == nil {
|
||||
utils.Fatalf("Error: can not convert hexadecimal string")
|
||||
}
|
||||
pub = crypto.ToECDSAPub(b)
|
||||
if !isKeyValid(pub) {
|
||||
utils.Fatalf("Error: invalid public key")
|
||||
if pub, err = crypto.UnmarshalPubkey(b); err != nil {
|
||||
utils.Fatalf("Error: invalid peer public key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Tran
|
|||
// Have to ensure that the new gas price is higher than the old gas
|
||||
// price as well as checking the percentage threshold to ensure that
|
||||
// this is accurate for low (Wei-level) gas price replacements
|
||||
if old.GasPrice().Cmp(tx.GasPrice()) >= 0 || threshold.Cmp(tx.GasPrice()) > 0 {
|
||||
if old.GasPriceCmp(tx) >= 0 || tx.GasPriceIntCmp(threshold) < 0 {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -383,7 +383,7 @@ func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
|||
|
||||
func (h priceHeap) Less(i, j int) bool {
|
||||
// Sort primarily by price, returning the cheaper one
|
||||
switch h[i].GasPrice().Cmp(h[j].GasPrice()) {
|
||||
switch h[i].GasPriceCmp(h[j]) {
|
||||
case -1:
|
||||
return true
|
||||
case 1:
|
||||
|
|
@ -460,7 +460,7 @@ func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transact
|
|||
continue
|
||||
}
|
||||
// Stop the discards if we've reached the threshold
|
||||
if tx.GasPrice().Cmp(threshold) >= 0 {
|
||||
if tx.GasPriceIntCmp(threshold) >= 0 {
|
||||
save = append(save, tx)
|
||||
break
|
||||
}
|
||||
|
|
@ -500,7 +500,7 @@ func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) boo
|
|||
return false
|
||||
}
|
||||
cheapest := []*types.Transaction(*l.items)[0]
|
||||
return cheapest.GasPrice().Cmp(tx.GasPrice()) >= 0
|
||||
return cheapest.GasPriceCmp(tx) >= 0
|
||||
}
|
||||
|
||||
// Discard finds a number of most underpriced transactions, removes them from the
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
|
|
@ -49,3 +50,21 @@ func TestStrictTxListAdd(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTxListAdd(t *testing.B) {
|
||||
// Generate a list of transactions to insert
|
||||
key, _ := crypto.GenerateKey()
|
||||
|
||||
txs := make(types.Transactions, 100000)
|
||||
for i := 0; i < len(txs); i++ {
|
||||
txs[i] = transaction(uint64(i), 0, key)
|
||||
}
|
||||
// Insert the transactions in a random order
|
||||
list := newTxList(true)
|
||||
priceLimit := big.NewInt(int64(DefaultTxPoolConfig.PriceLimit))
|
||||
t.ResetTimer()
|
||||
for _, v := range rand.Perm(len(txs)) {
|
||||
list.Add(txs[v], DefaultTxPoolConfig.PriceBump)
|
||||
list.Filter(priceLimit, DefaultTxPoolConfig.PriceBump, nil, nil)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -585,7 +585,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error {
|
|||
}
|
||||
// Drop non-local transactions under our own minimal accepted gas price
|
||||
local = local || pool.locals.contains(from) // account may be local even if the transaction arrived from the network
|
||||
if !local && pool.gasPrice.Cmp(tx.GasPrice()) > 0 {
|
||||
if !local && tx.GasPriceIntCmp(pool.gasPrice) < 0 {
|
||||
if !tx.IsSpecialTransaction() || (pool.IsSigner != nil && !pool.IsSigner(from)) {
|
||||
return ErrUnderpriced
|
||||
}
|
||||
|
|
@ -1337,8 +1337,8 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
|
|||
for _, tx := range forwards {
|
||||
hash := tx.Hash()
|
||||
pool.all.Remove(hash)
|
||||
log.Trace("Removed old queued transaction", "hash", hash)
|
||||
}
|
||||
log.Trace("Removed old queued transactions", "count", len(forwards))
|
||||
// Drop all transactions that are too costly (low balance or out of gas)
|
||||
var number *big.Int = nil
|
||||
if pool.chain.CurrentHeader() != nil {
|
||||
|
|
@ -1348,8 +1348,8 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
|
|||
for _, tx := range drops {
|
||||
hash := tx.Hash()
|
||||
pool.all.Remove(hash)
|
||||
log.Trace("Removed unpayable queued transaction", "hash", hash)
|
||||
}
|
||||
log.Trace("Removed unpayable queued transactions", "count", len(drops))
|
||||
queuedNofundsMeter.Mark(int64(len(drops)))
|
||||
|
||||
// Gather all executable transactions and promote them
|
||||
|
|
@ -1357,10 +1357,10 @@ func (pool *TxPool) promoteExecutables(accounts []common.Address) []*types.Trans
|
|||
for _, tx := range readies {
|
||||
hash := tx.Hash()
|
||||
if pool.promoteTx(addr, hash, tx) {
|
||||
log.Trace("Promoting queued transaction", "hash", hash)
|
||||
promoted = append(promoted, tx)
|
||||
}
|
||||
}
|
||||
log.Trace("Promoted queued transactions", "count", len(promoted))
|
||||
queuedGauge.Dec(int64(len(readies)))
|
||||
|
||||
// Drop all transactions over the allowed limit
|
||||
|
|
|
|||
|
|
@ -23,14 +23,16 @@ import (
|
|||
"io"
|
||||
"math/big"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
@ -155,10 +157,19 @@ func (h *Header) Size() common.StorageSize {
|
|||
return common.StorageSize(unsafe.Sizeof(*h)) + common.StorageSize(len(h.Extra)+(h.Difficulty.BitLen()+h.Number.BitLen()+h.Time.BitLen())/8)
|
||||
}
|
||||
|
||||
// hasherPool holds LegacyKeccak hashers.
|
||||
var hasherPool = sync.Pool{
|
||||
New: func() interface{} {
|
||||
return sha3.NewLegacyKeccak256()
|
||||
},
|
||||
}
|
||||
|
||||
func rlpHash(x interface{}) (h common.Hash) {
|
||||
hw := sha3.NewKeccak256()
|
||||
rlp.Encode(hw, x)
|
||||
hw.Sum(h[:0])
|
||||
sha := hasherPool.Get().(crypto.KeccakState)
|
||||
defer hasherPool.Put(sha)
|
||||
sha.Reset()
|
||||
rlp.Encode(sha, x)
|
||||
sha.Read(h[:])
|
||||
return h
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,9 +188,15 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
|
||||
func (tx *Transaction) Gas() uint64 { return tx.data.GasLimit }
|
||||
func (tx *Transaction) GasPrice() *big.Int { return new(big.Int).Set(tx.data.Price) }
|
||||
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
|
||||
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
|
||||
func (tx *Transaction) CheckNonce() bool { return true }
|
||||
func (tx *Transaction) GasPriceCmp(other *Transaction) int {
|
||||
return tx.data.Price.Cmp(other.data.Price)
|
||||
}
|
||||
func (tx *Transaction) GasPriceIntCmp(other *big.Int) int {
|
||||
return tx.data.Price.Cmp(other)
|
||||
}
|
||||
func (tx *Transaction) Value() *big.Int { return new(big.Int).Set(tx.data.Amount) }
|
||||
func (tx *Transaction) Nonce() uint64 { return tx.data.AccountNonce }
|
||||
func (tx *Transaction) CheckNonce() bool { return true }
|
||||
|
||||
// To returns the recipient address of the transaction.
|
||||
// It returns nil if the transaction is a contract creation.
|
||||
|
|
|
|||
116
crypto/crypto.go
116
crypto/crypto.go
|
|
@ -17,57 +17,81 @@
|
|||
package crypto
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/math"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto/sha3"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
//SignatureLength indicates the byte length required to carry a signature with recovery id.
|
||||
const SignatureLength = 64 + 1 // 64 bytes ECDSA signature + 1 byte recovery id
|
||||
|
||||
// RecoveryIDOffset points to the byte offset within the signature that contains the recovery id.
|
||||
const RecoveryIDOffset = 64
|
||||
|
||||
// DigestLength sets the signature digest exact length
|
||||
const DigestLength = 32
|
||||
|
||||
var (
|
||||
secp256k1_N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
|
||||
secp256k1_halfN = new(big.Int).Div(secp256k1_N, big.NewInt(2))
|
||||
secp256k1N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
|
||||
secp256k1halfN = new(big.Int).Div(secp256k1N, big.NewInt(2))
|
||||
)
|
||||
|
||||
var errInvalidPubkey = errors.New("invalid secp256k1 public key")
|
||||
|
||||
// KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
||||
// because it doesn't copy the internal state, but also modifies the internal state.
|
||||
type KeccakState interface {
|
||||
hash.Hash
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
|
||||
// Keccak256 calculates and returns the Keccak256 hash of the input data.
|
||||
func Keccak256(data ...[]byte) []byte {
|
||||
d := sha3.NewKeccak256()
|
||||
b := make([]byte, 32)
|
||||
d := sha3.NewLegacyKeccak256().(KeccakState)
|
||||
for _, b := range data {
|
||||
d.Write(b)
|
||||
}
|
||||
return d.Sum(nil)
|
||||
d.Read(b)
|
||||
return b
|
||||
}
|
||||
|
||||
// Keccak256Hash calculates and returns the Keccak256 hash of the input data,
|
||||
// converting it to an internal Hash data structure.
|
||||
func Keccak256Hash(data ...[]byte) (h common.Hash) {
|
||||
d := sha3.NewKeccak256()
|
||||
d := sha3.NewLegacyKeccak256().(KeccakState)
|
||||
for _, b := range data {
|
||||
d.Write(b)
|
||||
}
|
||||
d.Sum(h[:0])
|
||||
d.Read(h[:])
|
||||
return h
|
||||
}
|
||||
|
||||
// Keccak512 calculates and returns the Keccak512 hash of the input data.
|
||||
func Keccak512(data ...[]byte) []byte {
|
||||
d := sha3.NewKeccak512()
|
||||
d := sha3.NewLegacyKeccak512()
|
||||
for _, b := range data {
|
||||
d.Write(b)
|
||||
}
|
||||
return d.Sum(nil)
|
||||
}
|
||||
|
||||
// Creates an ethereum address given the bytes and the nonce
|
||||
// CreateAddress creates an ethereum address given the bytes and the nonce
|
||||
func CreateAddress(b common.Address, nonce uint64) common.Address {
|
||||
data, _ := rlp.EncodeToBytes([]interface{}{b, nonce})
|
||||
return common.BytesToAddress(Keccak256(data)[12:])
|
||||
|
|
@ -104,7 +128,7 @@ func toECDSA(d []byte, strict bool) (*ecdsa.PrivateKey, error) {
|
|||
priv.D = new(big.Int).SetBytes(d)
|
||||
|
||||
// The priv.D must < N
|
||||
if priv.D.Cmp(secp256k1_N) >= 0 {
|
||||
if priv.D.Cmp(secp256k1N) >= 0 {
|
||||
return nil, fmt.Errorf("invalid private key, >=N")
|
||||
}
|
||||
// The priv.D must not be zero or negative.
|
||||
|
|
@ -127,12 +151,13 @@ func FromECDSA(priv *ecdsa.PrivateKey) []byte {
|
|||
return math.PaddedBigBytes(priv.D, priv.Params().BitSize/8)
|
||||
}
|
||||
|
||||
func ToECDSAPub(pub []byte) *ecdsa.PublicKey {
|
||||
if len(pub) == 0 {
|
||||
return nil
|
||||
}
|
||||
// UnmarshalPubkey converts bytes to a secp256k1 public key.
|
||||
func UnmarshalPubkey(pub []byte) (*ecdsa.PublicKey, error) {
|
||||
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 {
|
||||
|
|
@ -145,38 +170,77 @@ func FromECDSAPub(pub *ecdsa.PublicKey) []byte {
|
|||
// HexToECDSA parses a secp256k1 private key.
|
||||
func HexToECDSA(hexkey string) (*ecdsa.PrivateKey, error) {
|
||||
b, err := hex.DecodeString(hexkey)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid hex string")
|
||||
if byteErr, ok := err.(hex.InvalidByteError); ok {
|
||||
return nil, fmt.Errorf("invalid hex character %q in private key", byte(byteErr))
|
||||
} else if err != nil {
|
||||
return nil, errors.New("invalid hex data for private key")
|
||||
}
|
||||
return ToECDSA(b)
|
||||
}
|
||||
|
||||
// LoadECDSA loads a secp256k1 private key from the given file.
|
||||
func LoadECDSA(file string) (*ecdsa.PrivateKey, error) {
|
||||
buf := make([]byte, 64)
|
||||
fd, err := os.Open(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer fd.Close()
|
||||
if _, err := io.ReadFull(fd, buf); err != nil {
|
||||
|
||||
r := bufio.NewReader(fd)
|
||||
buf := make([]byte, 64)
|
||||
n, err := readASCII(buf, r)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if n != len(buf) {
|
||||
return nil, fmt.Errorf("key file too short, want 64 hex characters")
|
||||
}
|
||||
if err := checkKeyFileEnd(r); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
key, err := hex.DecodeString(string(buf))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return HexToECDSA(string(buf))
|
||||
}
|
||||
|
||||
// readASCII reads into 'buf', stopping when the buffer is full or
|
||||
// when a non-printable control character is encountered.
|
||||
func readASCII(buf []byte, r *bufio.Reader) (n int, err error) {
|
||||
for ; n < len(buf); n++ {
|
||||
buf[n], err = r.ReadByte()
|
||||
switch {
|
||||
case err == io.EOF || buf[n] < '!':
|
||||
return n, nil
|
||||
case err != nil:
|
||||
return n, err
|
||||
}
|
||||
}
|
||||
return n, nil
|
||||
}
|
||||
|
||||
// checkKeyFileEnd skips over additional newlines at the end of a key file.
|
||||
func checkKeyFileEnd(r *bufio.Reader) error {
|
||||
for i := 0; ; i++ {
|
||||
b, err := r.ReadByte()
|
||||
switch {
|
||||
case err == io.EOF:
|
||||
return nil
|
||||
case err != nil:
|
||||
return err
|
||||
case b != '\n' && b != '\r':
|
||||
return fmt.Errorf("invalid character %q at end of key file", b)
|
||||
case i >= 2:
|
||||
return errors.New("key file too long, want 64 hex characters")
|
||||
}
|
||||
}
|
||||
return ToECDSA(key)
|
||||
}
|
||||
|
||||
// SaveECDSA saves a secp256k1 private key to the given file with
|
||||
// restrictive permissions. The key data is saved hex-encoded.
|
||||
func SaveECDSA(file string, key *ecdsa.PrivateKey) error {
|
||||
k := hex.EncodeToString(FromECDSA(key))
|
||||
return os.WriteFile(file, []byte(k), 0600)
|
||||
return ioutil.WriteFile(file, []byte(k), 0600)
|
||||
}
|
||||
|
||||
// GenerateKey generates a new private key.
|
||||
func GenerateKey() (*ecdsa.PrivateKey, error) {
|
||||
return ecdsa.GenerateKey(S256(), rand.Reader)
|
||||
}
|
||||
|
|
@ -189,11 +253,11 @@ func ValidateSignatureValues(v byte, r, s *big.Int, homestead bool) bool {
|
|||
}
|
||||
// reject upper range of s values (ECDSA malleability)
|
||||
// see discussion in secp256k1/libsecp256k1/include/secp256k1.h
|
||||
if homestead && s.Cmp(secp256k1_halfN) > 0 {
|
||||
if homestead && s.Cmp(secp256k1halfN) > 0 {
|
||||
return false
|
||||
}
|
||||
// Frontier: allow s to be in full N range
|
||||
return r.Cmp(secp256k1_N) < 0 && s.Cmp(secp256k1_N) < 0 && (v == 0 || v == 1)
|
||||
return r.Cmp(secp256k1N) < 0 && s.Cmp(secp256k1N) < 0 && (v == 0 || v == 1)
|
||||
}
|
||||
|
||||
func PubkeyToAddress(p ecdsa.PublicKey) common.Address {
|
||||
|
|
|
|||
|
|
@ -20,11 +20,14 @@ import (
|
|||
"bytes"
|
||||
"crypto/ecdsa"
|
||||
"encoding/hex"
|
||||
"io/ioutil"
|
||||
"math/big"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/common/hexutil"
|
||||
)
|
||||
|
||||
var testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791"
|
||||
|
|
@ -55,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) {
|
||||
key, _ := HexToECDSA(testPrivHex)
|
||||
addr := common.HexToAddress(testAddrHex)
|
||||
|
|
@ -68,7 +98,7 @@ func TestSign(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Errorf("ECRecover error: %s", err)
|
||||
}
|
||||
pubKey := ToECDSAPub(recoveredPub)
|
||||
pubKey, _ := UnmarshalPubkey(recoveredPub)
|
||||
recoveredAddr := PubkeyToAddress(*pubKey)
|
||||
if addr != recoveredAddr {
|
||||
t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr)
|
||||
|
|
@ -109,39 +139,82 @@ func TestNewContractAddress(t *testing.T) {
|
|||
checkAddr(t, common.HexToAddress("c9ddedf451bc62ce88bf9292afb13df35b670699"), caddr2)
|
||||
}
|
||||
|
||||
func TestLoadECDSAFile(t *testing.T) {
|
||||
keyBytes := common.FromHex(testPrivHex)
|
||||
fileName0 := "test_key0"
|
||||
fileName1 := "test_key1"
|
||||
checkKey := func(k *ecdsa.PrivateKey) {
|
||||
checkAddr(t, PubkeyToAddress(k.PublicKey), common.HexToAddress(testAddrHex))
|
||||
loadedKeyBytes := FromECDSA(k)
|
||||
if !bytes.Equal(loadedKeyBytes, keyBytes) {
|
||||
t.Fatalf("private key mismatch: want: %x have: %x", keyBytes, loadedKeyBytes)
|
||||
func TestLoadECDSA(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
err string
|
||||
}{
|
||||
// good
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"},
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n"},
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"},
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"},
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n"},
|
||||
{input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\r"},
|
||||
// bad
|
||||
{
|
||||
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde",
|
||||
err: "key file too short, want 64 hex characters",
|
||||
},
|
||||
{
|
||||
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcde\n",
|
||||
err: "key file too short, want 64 hex characters",
|
||||
},
|
||||
{
|
||||
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdeX",
|
||||
err: "invalid hex character 'X' in private key",
|
||||
},
|
||||
{
|
||||
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdefX",
|
||||
err: "invalid character 'X' at end of key file",
|
||||
},
|
||||
{
|
||||
input: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\n\n\n",
|
||||
err: "key file too long, want 64 hex characters",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
f, err := ioutil.TempFile("", "loadecdsa_test.*.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
filename := f.Name()
|
||||
f.WriteString(test.input)
|
||||
f.Close()
|
||||
|
||||
_, err = LoadECDSA(filename)
|
||||
switch {
|
||||
case err != nil && test.err == "":
|
||||
t.Fatalf("unexpected error for input %q:\n %v", test.input, err)
|
||||
case err != nil && err.Error() != test.err:
|
||||
t.Fatalf("wrong error for input %q:\n %v", test.input, err)
|
||||
case err == nil && test.err != "":
|
||||
t.Fatalf("LoadECDSA did not return error for input %q", test.input)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
os.WriteFile(fileName0, []byte(testPrivHex), 0600)
|
||||
defer os.Remove(fileName0)
|
||||
|
||||
key0, err := LoadECDSA(fileName0)
|
||||
func TestSaveECDSA(t *testing.T) {
|
||||
f, err := ioutil.TempFile("", "saveecdsa_test.*.txt")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
checkKey(key0)
|
||||
file := f.Name()
|
||||
f.Close()
|
||||
defer os.Remove(file)
|
||||
|
||||
// again, this time with SaveECDSA instead of manual save:
|
||||
err = SaveECDSA(fileName1, key0)
|
||||
key, _ := HexToECDSA(testPrivHex)
|
||||
if err := SaveECDSA(file, key); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
loaded, err := LoadECDSA(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fileName1)
|
||||
|
||||
key1, err := LoadECDSA(fileName1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
if !reflect.DeepEqual(key, loaded) {
|
||||
t.Fatal("loaded key not equal to saved key")
|
||||
}
|
||||
checkKey(key1)
|
||||
}
|
||||
|
||||
func TestValidateSignatureValues(t *testing.T) {
|
||||
|
|
@ -153,7 +226,7 @@ func TestValidateSignatureValues(t *testing.T) {
|
|||
minusOne := big.NewInt(-1)
|
||||
one := common.Big1
|
||||
zero := common.Big0
|
||||
secp256k1nMinus1 := new(big.Int).Sub(secp256k1_N, common.Big1)
|
||||
secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1)
|
||||
|
||||
// correct v,r,s
|
||||
check(true, 0, one, one)
|
||||
|
|
@ -180,9 +253,9 @@ func TestValidateSignatureValues(t *testing.T) {
|
|||
// correct sig with max r,s
|
||||
check(true, 0, secp256k1nMinus1, secp256k1nMinus1)
|
||||
// correct v, combinations of incorrect r,s at upper limit
|
||||
check(false, 0, secp256k1_N, secp256k1nMinus1)
|
||||
check(false, 0, secp256k1nMinus1, secp256k1_N)
|
||||
check(false, 0, secp256k1_N, secp256k1_N)
|
||||
check(false, 0, secp256k1N, secp256k1nMinus1)
|
||||
check(false, 0, secp256k1nMinus1, secp256k1N)
|
||||
check(false, 0, secp256k1N, secp256k1N)
|
||||
|
||||
// current callers ensures r,s cannot be negative, but let's test for that too
|
||||
// as crypto package could be used stand-alone
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ type transactionsByGasPrice []*types.Transaction
|
|||
|
||||
func (t transactionsByGasPrice) Len() int { return len(t) }
|
||||
func (t transactionsByGasPrice) Swap(i, j int) { t[i], t[j] = t[j], t[i] }
|
||||
func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPrice().Cmp(t[j].GasPrice()) < 0 }
|
||||
func (t transactionsByGasPrice) Less(i, j int) bool { return t[i].GasPriceCmp(t[j]) < 0 }
|
||||
|
||||
// getBlockPrices calculates the lowest transaction gas price in a given block
|
||||
// and sends it to the result channel. If the block is empty, price is nil.
|
||||
|
|
|
|||
|
|
@ -473,21 +473,19 @@ func (s *PrivateAccountAPI) Sign(ctx context.Context, data hexutil.Bytes, addr c
|
|||
//
|
||||
// https://github.com/XinFinOrg/XDPoSChain/wiki/Management-APIs#personal_ecRecover
|
||||
func (s *PrivateAccountAPI) EcRecover(ctx context.Context, data, sig hexutil.Bytes) (common.Address, error) {
|
||||
if len(sig) != 65 {
|
||||
return common.Address{}, fmt.Errorf("signature must be 65 bytes long")
|
||||
if len(sig) != crypto.SignatureLength {
|
||||
return common.Address{}, fmt.Errorf("signature must be %d bytes long", crypto.SignatureLength)
|
||||
}
|
||||
if sig[64] != 27 && sig[64] != 28 {
|
||||
if sig[crypto.RecoveryIDOffset] != 27 && sig[crypto.RecoveryIDOffset] != 28 {
|
||||
return common.Address{}, fmt.Errorf("invalid Ethereum signature (V is not 27 or 28)")
|
||||
}
|
||||
sig[64] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||
sig[crypto.RecoveryIDOffset] -= 27 // Transform yellow paper V from 27/28 to 0/1
|
||||
|
||||
rpk, err := crypto.Ecrecover(signHash(data), sig)
|
||||
rpk, err := crypto.SigToPub(accounts.TextHash(data), sig)
|
||||
if err != nil {
|
||||
return common.Address{}, err
|
||||
}
|
||||
pubKey := crypto.ToECDSAPub(rpk)
|
||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
||||
return recoveredAddr, nil
|
||||
return crypto.PubkeyToAddress(*rpk), nil
|
||||
}
|
||||
|
||||
// SignAndSendTransaction was renamed to SendTransaction. This method is deprecated
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
// TODO: fewer pointless conversions
|
||||
pub := crypto.ToECDSAPub(pubKey65)
|
||||
if pub.X == nil {
|
||||
return nil, fmt.Errorf("invalid public key")
|
||||
pub, err := crypto.UnmarshalPubkey(pubKey65)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ecies.ImportECDSAPublic(pub), nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ type PayProfile struct {
|
|||
lock sync.RWMutex
|
||||
}
|
||||
|
||||
//create params with default values
|
||||
// create params with default values
|
||||
func NewDefaultSwapParams() *SwapParams {
|
||||
return &SwapParams{
|
||||
PayProfile: &PayProfile{},
|
||||
|
|
@ -102,8 +102,8 @@ func NewDefaultSwapParams() *SwapParams {
|
|||
}
|
||||
}
|
||||
|
||||
//this can only finally be set after all config options (file, cmd line, env vars)
|
||||
//have been evaluated
|
||||
// this can only finally be set after all config options (file, cmd line, env vars)
|
||||
// have been evaluated
|
||||
func (self *SwapParams) Init(contract common.Address, prvkey *ecdsa.PrivateKey) {
|
||||
pubkey := &prvkey.PublicKey
|
||||
|
||||
|
|
@ -141,8 +141,12 @@ func NewSwap(local *SwapParams, remote *SwapProfile, backend chequebook.Backend,
|
|||
if !ok {
|
||||
log.Info(fmt.Sprintf("invalid contract %v for peer %v: %v)", remote.Contract.Hex()[:8], proto, err))
|
||||
} else {
|
||||
pub, err := crypto.UnmarshalPubkey(common.FromHex(remote.PublicKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// 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, pub, backend)
|
||||
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))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/common"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
|
@ -46,7 +47,7 @@ type leaf struct {
|
|||
// processed sequentially - onleaf will never be called in parallel or out of order.
|
||||
type committer struct {
|
||||
tmp sliceBuffer
|
||||
sha keccakState
|
||||
sha crypto.KeccakState
|
||||
|
||||
onleaf LeafCallback
|
||||
leafCh chan *leaf
|
||||
|
|
@ -57,7 +58,7 @@ var committerPool = sync.Pool{
|
|||
New: func() interface{} {
|
||||
return &committer{
|
||||
tmp: make(sliceBuffer, 0, 550), // cap is as large as a full FullNode.
|
||||
sha: sha3.NewLegacyKeccak256().(keccakState),
|
||||
sha: sha3.NewLegacyKeccak256().(crypto.KeccakState),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,21 +17,13 @@
|
|||
package trie
|
||||
|
||||
import (
|
||||
"hash"
|
||||
"sync"
|
||||
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
"github.com/XinFinOrg/XDPoSChain/rlp"
|
||||
"golang.org/x/crypto/sha3"
|
||||
)
|
||||
|
||||
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
||||
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
||||
// because it doesn't copy the internal state, but also modifies the internal state.
|
||||
type keccakState interface {
|
||||
hash.Hash
|
||||
Read([]byte) (int, error)
|
||||
}
|
||||
|
||||
type sliceBuffer []byte
|
||||
|
||||
func (b *sliceBuffer) Write(data []byte) (n int, err error) {
|
||||
|
|
@ -46,7 +38,7 @@ func (b *sliceBuffer) Reset() {
|
|||
// hasher is a type used for the trie Hash operation. A hasher has some
|
||||
// internal preallocated temp space
|
||||
type hasher struct {
|
||||
sha keccakState
|
||||
sha crypto.KeccakState
|
||||
tmp sliceBuffer
|
||||
parallel bool // Whether to use paralallel threads when hashing
|
||||
}
|
||||
|
|
@ -56,7 +48,7 @@ var hasherPool = sync.Pool{
|
|||
New: func() interface{} {
|
||||
return &hasher{
|
||||
tmp: make(sliceBuffer, 0, 550), // cap is as large as a full FullNode.
|
||||
sha: sha3.NewLegacyKeccak256().(keccakState),
|
||||
sha: sha3.NewLegacyKeccak256().(crypto.KeccakState),
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -256,8 +256,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
|||
|
||||
// Set asymmetric key that is used to encrypt the message
|
||||
if pubKeyGiven {
|
||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||
return false, ErrInvalidPublicKey
|
||||
}
|
||||
}
|
||||
|
|
@ -333,8 +332,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||
}
|
||||
|
||||
if len(crit.Sig) > 0 {
|
||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||
return nil, ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
@ -517,8 +515,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||
}
|
||||
|
||||
if len(req.Sig) > 0 {
|
||||
src = crypto.ToECDSAPub(req.Sig)
|
||||
if !ValidatePublicKey(src) {
|
||||
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||
return "", ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -275,8 +275,7 @@ func (api *PublicWhisperAPI) Post(ctx context.Context, req NewMessage) (bool, er
|
|||
|
||||
// Set asymmetric key that is used to encrypt the message
|
||||
if pubKeyGiven {
|
||||
params.Dst = crypto.ToECDSAPub(req.PublicKey)
|
||||
if !ValidatePublicKey(params.Dst) {
|
||||
if params.Dst, err = crypto.UnmarshalPubkey(req.PublicKey); err != nil {
|
||||
return false, ErrInvalidPublicKey
|
||||
}
|
||||
}
|
||||
|
|
@ -352,8 +351,7 @@ func (api *PublicWhisperAPI) Messages(ctx context.Context, crit Criteria) (*rpc.
|
|||
}
|
||||
|
||||
if len(crit.Sig) > 0 {
|
||||
filter.Src = crypto.ToECDSAPub(crit.Sig)
|
||||
if !ValidatePublicKey(filter.Src) {
|
||||
if filter.Src, err = crypto.UnmarshalPubkey(crit.Sig); err != nil {
|
||||
return nil, ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
@ -536,8 +534,7 @@ func (api *PublicWhisperAPI) NewMessageFilter(req Criteria) (string, error) {
|
|||
}
|
||||
|
||||
if len(req.Sig) > 0 {
|
||||
src = crypto.ToECDSAPub(req.Sig)
|
||||
if !ValidatePublicKey(src) {
|
||||
if src, err = crypto.UnmarshalPubkey(req.Sig); err != nil {
|
||||
return "", ErrInvalidSigningPubKey
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue