core/types: cache computed transaction values

This commit is contained in:
Felix Lange 2015-06-25 14:45:54 +02:00 committed by Jeffrey Wilcke
parent 8743cc1c1c
commit 11b8d1df59

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"sync/atomic"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
@ -20,6 +21,10 @@ func IsContractAddr(addr []byte) bool {
type Transaction struct { type Transaction struct {
data txdata data txdata
// caches
hash atomic.Value
size atomic.Value
from atomic.Value
} }
type txdata struct { type txdata struct {
@ -88,7 +93,12 @@ func (tx *Transaction) EncodeRLP(w io.Writer) error {
} }
func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
return s.Decode(&tx.data) _, size, _ := s.Kind()
err := s.Decode(&tx.data)
if err == nil {
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
}
return err
} }
func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) } func (tx *Transaction) Data() []byte { return common.CopyBytes(tx.data.Payload) }
@ -107,6 +117,9 @@ func (tx *Transaction) To() *common.Address {
} }
func (tx *Transaction) Hash() common.Hash { func (tx *Transaction) Hash() common.Hash {
if hash := tx.hash.Load(); hash != nil {
return hash.(common.Hash)
}
v := rlpHash([]interface{}{ v := rlpHash([]interface{}{
tx.data.AccountNonce, tx.data.AccountNonce,
tx.data.Price, tx.data.Price,
@ -115,21 +128,31 @@ func (tx *Transaction) Hash() common.Hash {
tx.data.Amount, tx.data.Amount,
tx.data.Payload, tx.data.Payload,
}) })
tx.hash.Store(v)
return v return v
} }
func (tx *Transaction) Size() common.StorageSize { func (tx *Transaction) Size() common.StorageSize {
v, _, _ := rlp.EncodeToReader(&tx.data) if size := tx.size.Load(); size != nil {
return common.StorageSize(v) return size.(common.StorageSize)
}
c := writeCounter(0)
rlp.Encode(&c, &tx.data)
tx.size.Store(common.StorageSize(c))
return common.StorageSize(c)
} }
func (tx *Transaction) From() (common.Address, error) { func (tx *Transaction) From() (common.Address, error) {
pubkey, err := tx.PublicKey() if from := tx.from.Load(); from != nil {
return from.(common.Address), nil
}
pubkey, err := tx.publicKey()
if err != nil { if err != nil {
return common.Address{}, err return common.Address{}, err
} }
var addr common.Address var addr common.Address
copy(addr[:], crypto.Sha3(pubkey[1:])[12:]) copy(addr[:], crypto.Sha3(pubkey[1:])[12:])
tx.from.Store(addr)
return addr, nil return addr, nil
} }
@ -144,7 +167,7 @@ func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) {
return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S) return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
} }
func (tx *Transaction) PublicKey() ([]byte, error) { func (tx *Transaction) publicKey() ([]byte, error) {
if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S) { if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S) {
return nil, errors.New("invalid v, r, s values") return nil, errors.New("invalid v, r, s values")
} }