mirror of https://github.com/poanetwork/quorum.git
Merge remote-tracking branch 'remotes/geth/release/1.8' into merge-193
changes related to merge conflicts
This commit is contained in:
parent
c3c479d2aa
commit
7c548e0f74
|
@ -100,247 +100,6 @@ func (arguments Arguments) Unpack(v interface{}, data []byte) error {
|
||||||
return arguments.unpackAtomic(v, marshalledValues)
|
return arguments.unpackAtomic(v, marshalledValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
|
|
||||||
|
|
||||||
var (
|
|
||||||
value = reflect.ValueOf(v).Elem()
|
|
||||||
typ = value.Type()
|
|
||||||
kind = value.Kind()
|
|
||||||
)
|
|
||||||
|
|
||||||
if err := requireUnpackKind(value, typ, kind, arguments); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
// If the output interface is a struct, make sure names don't collide
|
|
||||||
if kind == reflect.Struct {
|
|
||||||
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for i, arg := range arguments.NonIndexed() {
|
|
||||||
|
|
||||||
reflectValue := reflect.ValueOf(marshalledValues[i])
|
|
||||||
|
|
||||||
switch kind {
|
|
||||||
case reflect.Struct:
|
|
||||||
err := unpackStruct(value, reflectValue, arg)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
case reflect.Slice, reflect.Array:
|
|
||||||
if value.Len() < i {
|
|
||||||
return fmt.Errorf("abi: insufficient number of arguments for unpack, want %d, got %d", len(arguments), value.Len())
|
|
||||||
}
|
|
||||||
v := value.Index(i)
|
|
||||||
if err := requireAssignable(v, reflectValue); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := set(v.Elem(), reflectValue, arg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("abi:[2] cannot unmarshal tuple in to %v", typ)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// unpackAtomic unpacks ( hexdata -> go ) a single value
|
|
||||||
func (arguments Arguments) unpackAtomic(v interface{}, marshalledValues []interface{}) error {
|
|
||||||
if len(marshalledValues) != 1 {
|
|
||||||
return fmt.Errorf("abi: wrong length, expected single value, got %d", len(marshalledValues))
|
|
||||||
}
|
|
||||||
elem := reflect.ValueOf(v).Elem()
|
|
||||||
kind := elem.Kind()
|
|
||||||
reflectValue := reflect.ValueOf(marshalledValues[0])
|
|
||||||
|
|
||||||
if kind == reflect.Struct {
|
|
||||||
//make sure names don't collide
|
|
||||||
if err := requireUniqueStructFieldNames(arguments); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return unpackStruct(elem, reflectValue, arguments[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
return set(elem, reflectValue, arguments.NonIndexed()[0])
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Computes the full size of an array;
|
|
||||||
// i.e. counting nested arrays, which count towards size for unpacking.
|
|
||||||
func getArraySize(arr *Type) int {
|
|
||||||
size := arr.Size
|
|
||||||
// Arrays can be nested, with each element being the same size
|
|
||||||
arr = arr.Elem
|
|
||||||
for arr.T == ArrayTy {
|
|
||||||
// Keep multiplying by elem.Size while the elem is an array.
|
|
||||||
size *= arr.Size
|
|
||||||
arr = arr.Elem
|
|
||||||
}
|
|
||||||
// Now we have the full array size, including its children.
|
|
||||||
return size
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnpackValues can be used to unpack ABI-encoded hexdata according to the ABI-specification,
|
|
||||||
// without supplying a struct to unpack into. Instead, this method returns a list containing the
|
|
||||||
// values. An atomic argument will be a list with one element.
|
|
||||||
func (arguments Arguments) UnpackValues(data []byte) ([]interface{}, error) {
|
|
||||||
retval := make([]interface{}, 0, arguments.LengthNonIndexed())
|
|
||||||
virtualArgs := 0
|
|
||||||
for index, arg := range arguments.NonIndexed() {
|
|
||||||
marshalledValue, err := toGoType((index+virtualArgs)*32, arg.Type, data)
|
|
||||||
if arg.Type.T == ArrayTy {
|
|
||||||
// If we have a static array, like [3]uint256, these are coded as
|
|
||||||
// just like uint256,uint256,uint256.
|
|
||||||
// This means that we need to add two 'virtual' arguments when
|
|
||||||
// we count the index from now on.
|
|
||||||
//
|
|
||||||
// Array values nested multiple levels deep are also encoded inline:
|
|
||||||
// [2][3]uint256: uint256,uint256,uint256,uint256,uint256,uint256
|
|
||||||
//
|
|
||||||
// Calculate the full array size to get the correct offset for the next argument.
|
|
||||||
// Decrement it by 1, as the normal index increment is still applied.
|
|
||||||
virtualArgs += getArraySize(&arg.Type) - 1
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
retval = append(retval, marshalledValue)
|
|
||||||
}
|
|
||||||
return retval, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PackValues performs the operation Go format -> Hexdata
|
|
||||||
// It is the semantic opposite of UnpackValues
|
|
||||||
func (arguments Arguments) PackValues(args []interface{}) ([]byte, error) {
|
|
||||||
return arguments.Pack(args...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pack performs the operation Go format -> Hexdata
|
|
||||||
func (arguments Arguments) Pack(args ...interface{}) ([]byte, error) {
|
|
||||||
// Make sure arguments match up and pack them
|
|
||||||
abiArgs := arguments
|
|
||||||
if len(args) != len(abiArgs) {
|
|
||||||
return nil, fmt.Errorf("argument count mismatch: %d for %d", len(args), len(abiArgs))
|
|
||||||
}
|
|
||||||
// variable input is the output appended at the end of packed
|
|
||||||
// output. This is used for strings and bytes types input.
|
|
||||||
var variableInput []byte
|
|
||||||
|
|
||||||
// input offset is the bytes offset for packed output
|
|
||||||
inputOffset := 0
|
|
||||||
for _, abiArg := range abiArgs {
|
|
||||||
if abiArg.Type.T == ArrayTy {
|
|
||||||
inputOffset += 32 * abiArg.Type.Size
|
|
||||||
} else {
|
|
||||||
inputOffset += 32
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var ret []byte
|
|
||||||
for i, a := range args {
|
|
||||||
input := abiArgs[i]
|
|
||||||
// pack the input
|
|
||||||
packed, err := input.Type.pack(reflect.ValueOf(a))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
// check for a slice type (string, bytes, slice)
|
|
||||||
if input.Type.requiresLengthPrefix() {
|
|
||||||
// calculate the offset
|
|
||||||
offset := inputOffset + len(variableInput)
|
|
||||||
// set the offset
|
|
||||||
ret = append(ret, packNum(reflect.ValueOf(offset))...)
|
|
||||||
// Append the packed output to the variable input. The variable input
|
|
||||||
// will be appended at the end of the input.
|
|
||||||
variableInput = append(variableInput, packed...)
|
|
||||||
} else {
|
|
||||||
// append the packed value to the input
|
|
||||||
ret = append(ret, packed...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// append the variable input at the end of the packed input
|
|
||||||
ret = append(ret, variableInput...)
|
|
||||||
|
|
||||||
return ret, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// capitalise makes the first character of a string upper case, also removing any
|
|
||||||
// prefixing underscores from the variable names.
|
|
||||||
func capitalise(input string) string {
|
|
||||||
for len(input) > 0 && input[0] == '_' {
|
|
||||||
input = input[1:]
|
|
||||||
}
|
|
||||||
if len(input) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
|
||||||
}
|
|
||||||
|
|
||||||
//unpackStruct extracts each argument into its corresponding struct field
|
|
||||||
func unpackStruct(value, reflectValue reflect.Value, arg Argument) error {
|
|
||||||
name := capitalise(arg.Name)
|
|
||||||
typ := value.Type()
|
|
||||||
for j := 0; j < typ.NumField(); j++ {
|
|
||||||
// TODO read tags: `abi:"fieldName"`
|
|
||||||
if typ.Field(j).Name == name {
|
|
||||||
if err := set(value.Field(j), reflectValue, arg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
argument.Name = extarg.Name
|
|
||||||
argument.Indexed = extarg.Indexed
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// LengthNonIndexed returns the number of arguments when not counting 'indexed' ones. Only events
|
|
||||||
// can ever have 'indexed' arguments, it should always be false on arguments for method input/output
|
|
||||||
func (arguments Arguments) LengthNonIndexed() int {
|
|
||||||
out := 0
|
|
||||||
for _, arg := range arguments {
|
|
||||||
if !arg.Indexed {
|
|
||||||
out++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// NonIndexed returns the arguments with indexed arguments filtered out
|
|
||||||
func (arguments Arguments) NonIndexed() Arguments {
|
|
||||||
var ret []Argument
|
|
||||||
for _, arg := range arguments {
|
|
||||||
if !arg.Indexed {
|
|
||||||
ret = append(ret, arg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// isTuple returns true for non-atomic constructs, like (uint,uint) or uint[]
|
|
||||||
func (arguments Arguments) isTuple() bool {
|
|
||||||
return len(arguments) > 1
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unpack performs the operation hexdata -> Go format
|
|
||||||
func (arguments Arguments) Unpack(v interface{}, data []byte) error {
|
|
||||||
|
|
||||||
// make sure the passed value is arguments pointer
|
|
||||||
if reflect.Ptr != reflect.ValueOf(v).Kind() {
|
|
||||||
return fmt.Errorf("abi: Unpack(non-pointer %T)", v)
|
|
||||||
}
|
|
||||||
marshalledValues, err := arguments.UnpackValues(data)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if arguments.isTuple() {
|
|
||||||
return arguments.unpackTuple(v, marshalledValues)
|
|
||||||
}
|
|
||||||
return arguments.unpackAtomic(v, marshalledValues)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
|
func (arguments Arguments) unpackTuple(v interface{}, marshalledValues []interface{}) error {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -103,7 +103,7 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
|
|
||||||
func (b *SimulatedBackend) rollback() {
|
func (b *SimulatedBackend) rollback() {
|
||||||
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
blocks, _ := core.GenerateChain(b.config, b.blockchain.CurrentBlock(), ethash.NewFaker(), b.database, 1, func(int, *core.BlockGen) {})
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
||||||
|
@ -117,7 +117,7 @@ func (b *SimulatedBackend) CodeAt(ctx context.Context, contract common.Address,
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return nil, errBlockNumberUnsupported
|
return nil, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
return statedb.GetCode(contract), nil
|
return statedb.GetCode(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ func (b *SimulatedBackend) BalanceAt(ctx context.Context, contract common.Addres
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return nil, errBlockNumberUnsupported
|
return nil, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
return statedb.GetBalance(contract), nil
|
return statedb.GetBalance(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,7 +141,7 @@ func (b *SimulatedBackend) NonceAt(ctx context.Context, contract common.Address,
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return 0, errBlockNumberUnsupported
|
return 0, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
return statedb.GetNonce(contract), nil
|
return statedb.GetNonce(contract), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return nil, errBlockNumberUnsupported
|
return nil, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
val := statedb.GetState(contract, key)
|
val := statedb.GetState(contract, key)
|
||||||
return val[:], nil
|
return val[:], nil
|
||||||
}
|
}
|
||||||
|
@ -180,11 +180,11 @@ func (b *SimulatedBackend) CallContract(ctx context.Context, call ethereum.CallM
|
||||||
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
if blockNumber != nil && blockNumber.Cmp(b.blockchain.CurrentBlock().Number()) != 0 {
|
||||||
return nil, errBlockNumberUnsupported
|
return nil, errBlockNumberUnsupported
|
||||||
}
|
}
|
||||||
state, err := b.blockchain.State()
|
state, _, err := b.blockchain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state)
|
rval, _, _, err := b.callContract(ctx, call, b.blockchain.CurrentBlock(), state, state)
|
||||||
return rval, err
|
return rval, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +194,7 @@ func (b *SimulatedBackend) PendingCallContract(ctx context.Context, call ethereu
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
defer b.pendingState.RevertToSnapshot(b.pendingState.Snapshot())
|
||||||
|
|
||||||
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
rval, _, _, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState, b.pendingState)
|
||||||
return rval, err
|
return rval, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
call.Gas = gas
|
call.Gas = gas
|
||||||
|
|
||||||
snapshot := b.pendingState.Snapshot()
|
snapshot := b.pendingState.Snapshot()
|
||||||
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState)
|
_, _, failed, err := b.callContract(ctx, call, b.pendingBlock, b.pendingState, b.pendingState)
|
||||||
b.pendingState.RevertToSnapshot(snapshot)
|
b.pendingState.RevertToSnapshot(snapshot)
|
||||||
|
|
||||||
if err != nil || failed {
|
if err != nil || failed {
|
||||||
|
@ -265,7 +265,7 @@ func (b *SimulatedBackend) EstimateGas(ctx context.Context, call ethereum.CallMs
|
||||||
|
|
||||||
// callContract implements common code between normal and pending contract calls.
|
// callContract implements common code between normal and pending contract calls.
|
||||||
// state is modified during execution, make sure to copy it if necessary.
|
// state is modified during execution, make sure to copy it if necessary.
|
||||||
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB) ([]byte, uint64, bool, error) {
|
func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallMsg, block *types.Block, statedb *state.StateDB, privateState *state.StateDB) ([]byte, uint64, bool, error) {
|
||||||
// Ensure message is initialized properly.
|
// Ensure message is initialized properly.
|
||||||
if call.GasPrice == nil {
|
if call.GasPrice == nil {
|
||||||
call.GasPrice = big.NewInt(1)
|
call.GasPrice = big.NewInt(1)
|
||||||
|
@ -285,7 +285,7 @@ func (b *SimulatedBackend) callContract(ctx context.Context, call ethereum.CallM
|
||||||
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
|
evmContext := core.NewEVMContext(msg, block.Header(), b.blockchain, nil)
|
||||||
// Create a new environment which holds all relevant information
|
// Create a new environment which holds all relevant information
|
||||||
// about the transaction and calling mechanisms.
|
// about the transaction and calling mechanisms.
|
||||||
vmenv := vm.NewEVM(evmContext, statedb, b.config, vm.Config{})
|
vmenv := vm.NewEVM(evmContext, statedb, privateState, b.config, vm.Config{})
|
||||||
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
|
gaspool := new(core.GasPool).AddGas(math.MaxUint64)
|
||||||
|
|
||||||
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
return core.NewStateTransition(vmenv, msg, gaspool).TransitionDb()
|
||||||
|
@ -312,7 +312,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
}
|
}
|
||||||
block.AddTxWithChain(b.blockchain, tx)
|
block.AddTxWithChain(b.blockchain, tx)
|
||||||
})
|
})
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
||||||
|
@ -391,7 +391,7 @@ func (b *SimulatedBackend) AdjustTime(adjustment time.Duration) error {
|
||||||
}
|
}
|
||||||
block.OffsetTime(int64(adjustment.Seconds()))
|
block.OffsetTime(int64(adjustment.Seconds()))
|
||||||
})
|
})
|
||||||
statedb, _ := b.blockchain.State()
|
statedb, _, _ := b.blockchain.State()
|
||||||
|
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), statedb.Database())
|
||||||
|
|
|
@ -471,7 +471,7 @@ func (f *faucet) apiHandler(conn *websocket.Conn) {
|
||||||
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
|
amount = new(big.Int).Div(amount, new(big.Int).Exp(big.NewInt(2), big.NewInt(int64(msg.Tier)), nil))
|
||||||
|
|
||||||
tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
|
tx := types.NewTransaction(f.nonce+uint64(len(f.reqs)), address, amount, 21000, f.price, nil)
|
||||||
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID)
|
signed, err := f.keystore.SignTx(f.account, tx, f.config.ChainID, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
f.lock.Unlock()
|
f.lock.Unlock()
|
||||||
if err = sendError(conn, err); err != nil {
|
if err = sendError(conn, err); err != nil {
|
||||||
|
|
|
@ -58,6 +58,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -1228,7 +1229,8 @@ func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterEthService adds an Ethereum client to the stack.
|
// RegisterEthService adds an Ethereum client to the stack.
|
||||||
func RegisterEthService(stack *node.Node, cfg *eth.Config) {
|
func RegisterEthService(stack *node.Node, cfg *eth.Config) <-chan *eth.Ethereum {
|
||||||
|
nodeChan := make(chan *eth.Ethereum, 1)
|
||||||
var err error
|
var err error
|
||||||
if cfg.SyncMode == downloader.LightSync {
|
if cfg.SyncMode == downloader.LightSync {
|
||||||
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
|
||||||
|
@ -1241,6 +1243,7 @@ func RegisterEthService(stack *node.Node, cfg *eth.Config) {
|
||||||
ls, _ := les.NewLesServer(fullNode, cfg)
|
ls, _ := les.NewLesServer(fullNode, cfg)
|
||||||
fullNode.AddLesServer(ls)
|
fullNode.AddLesServer(ls)
|
||||||
}
|
}
|
||||||
|
nodeChan <- fullNode
|
||||||
return fullNode, err
|
return fullNode, err
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,8 @@ func BytesToHash(b []byte) Hash {
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToHash(s string) Hash { return BytesToHash([]byte(s)) } // dep: Istanbul
|
||||||
|
|
||||||
// BigToHash sets byte representation of b to hash.
|
// BigToHash sets byte representation of b to hash.
|
||||||
// If b is larger than len(h), b will be cropped from the left.
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) }
|
||||||
|
@ -111,6 +113,10 @@ func (h *Hash) SetBytes(b []byte) {
|
||||||
copy(h[HashLength-len(b):], b)
|
copy(h[HashLength-len(b):], b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EmptyHash(h Hash) bool {
|
||||||
|
return h == Hash{}
|
||||||
|
}
|
||||||
|
|
||||||
// Generate implements testing/quick.Generator.
|
// Generate implements testing/quick.Generator.
|
||||||
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
func (h Hash) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||||
m := rand.Intn(len(h))
|
m := rand.Intn(len(h))
|
||||||
|
@ -146,6 +152,9 @@ func BytesToAddress(b []byte) Address {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func StringToAddress(s string) Address { return BytesToAddress([]byte(s)) } // dep: Istanbul
|
||||||
|
|
||||||
|
|
||||||
// BigToAddress returns Address with byte values of b.
|
// BigToAddress returns Address with byte values of b.
|
||||||
// If b is larger than len(h), b will be cropped from the left.
|
// If b is larger than len(h), b will be cropped from the left.
|
||||||
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
|
func BigToAddress(b *big.Int) Address { return BytesToAddress(b.Bytes()) }
|
||||||
|
|
|
@ -545,7 +545,7 @@ func (ethash *Ethash) Prepare(chain consensus.ChainReader, header *types.Header)
|
||||||
// setting the final state and assembling the block.
|
// setting the final state and assembling the block.
|
||||||
func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
func (ethash *Ethash) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) {
|
||||||
// Accumulate any block and uncle rewards and commit the final state root
|
// Accumulate any block and uncle rewards and commit the final state root
|
||||||
accumulateRewards(chain.Config(), state, header, uncles)
|
AccumulateRewards(chain.Config(), state, header, uncles)
|
||||||
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number))
|
||||||
|
|
||||||
// Header seems complete, assemble into a block and return
|
// Header seems complete, assemble into a block and return
|
||||||
|
@ -561,7 +561,7 @@ var (
|
||||||
// AccumulateRewards credits the coinbase of the given block with the mining
|
// AccumulateRewards credits the coinbase of the given block with the mining
|
||||||
// reward. The total reward consists of the static block reward and rewards for
|
// reward. The total reward consists of the static block reward and rewards for
|
||||||
// included uncles. The coinbase of each uncle block is also rewarded.
|
// included uncles. The coinbase of each uncle block is also rewarded.
|
||||||
func accumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
func AccumulateRewards(config *params.ChainConfig, state *state.StateDB, header *types.Header, uncles []*types.Header) {
|
||||||
// Select the correct block reward based on chain progression
|
// Select the correct block reward based on chain progression
|
||||||
blockReward := FrontierBlockReward
|
blockReward := FrontierBlockReward
|
||||||
if config.IsByzantium(header.Number) {
|
if config.IsByzantium(header.Number) {
|
||||||
|
|
|
@ -701,9 +701,9 @@ func (bc *BlockChain) Stop() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for !bc.triegc.Empty() {
|
for !bc.triegc.Empty() {
|
||||||
triedb.Dereference(bc.triegc.PopItem().(common.Hash), common.Hash{})
|
triedb.Dereference(bc.triegc.PopItem().(common.Hash))
|
||||||
}
|
}
|
||||||
if size := triedb.Size(); size != 0 {
|
if size, _ := triedb.Size(); size != 0 {
|
||||||
log.Error("Dangling trie nodes after full cleanup")
|
log.Error("Dangling trie nodes after full cleanup")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -976,7 +976,7 @@ func (bc *BlockChain) WriteBlockWithState(block *types.Block, receipts []*types.
|
||||||
bc.triegc.Push(root, number)
|
bc.triegc.Push(root, number)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
triedb.Dereference(root.(common.Hash), common.Hash{})
|
triedb.Dereference(root.(common.Hash))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1486,6 +1486,11 @@ func (bc *BlockChain) BadBlocks() []*types.Block {
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HasBadBlock returns whether the block with the hash is a bad block. dep: Istanbul
|
||||||
|
func (bc *BlockChain) HasBadBlock(hash common.Hash) bool {
|
||||||
|
return bc.badBlocks.Contains(hash)
|
||||||
|
}
|
||||||
|
|
||||||
// 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.Hash(), block)
|
bc.badBlocks.Add(block.Hash(), block)
|
||||||
|
|
|
@ -1208,7 +1208,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil {
|
if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if st, _ := blockchain.State(); !st.Exist(theAddr) {
|
if st, _, _ := blockchain.State(); !st.Exist(theAddr) {
|
||||||
t.Error("expected account to exist")
|
t.Error("expected account to exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,7 +1216,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
if _, err := blockchain.InsertChain(types.Blocks{blocks[1]}); err != nil {
|
if _, err := blockchain.InsertChain(types.Blocks{blocks[1]}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if st, _ := blockchain.State(); st.Exist(theAddr) {
|
if st, _, _ := blockchain.State(); st.Exist(theAddr) {
|
||||||
t.Error("account should not exist")
|
t.Error("account should not exist")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1224,7 +1224,7 @@ func TestEIP161AccountRemoval(t *testing.T) {
|
||||||
if _, err := blockchain.InsertChain(types.Blocks{blocks[2]}); err != nil {
|
if _, err := blockchain.InsertChain(types.Blocks{blocks[2]}); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if st, _ := blockchain.State(); st.Exist(theAddr) {
|
if st, _, _ := blockchain.State(); st.Exist(theAddr) {
|
||||||
t.Error("account should not exist")
|
t.Error("account should not exist")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,7 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) {
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
|
b.statedb.Prepare(tx.Hash(), common.Hash{}, len(b.txs))
|
||||||
receipt, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
receipt, _, _, err := ApplyTransaction(b.config, bc, &b.header.Coinbase, b.gasPool, b.statedb, b.statedb, b.header, tx, &b.header.GasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,665 @@
|
||||||
|
// Copyright 2015 The go-ethereum Authors
|
||||||
|
// This file is part of the go-ethereum library.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU Lesser General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package core
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/binary"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DatabaseReader wraps the Get method of a backing data store.
|
||||||
|
type DatabaseReader interface {
|
||||||
|
Get(key []byte) (value []byte, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DatabaseDeleter wraps the Delete method of a backing data store.
|
||||||
|
type DatabaseDeleter interface {
|
||||||
|
Delete(key []byte) error
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
headHeaderKey = []byte("LastHeader")
|
||||||
|
headBlockKey = []byte("LastBlock")
|
||||||
|
headFastKey = []byte("LastFast")
|
||||||
|
|
||||||
|
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`).
|
||||||
|
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||||
|
tdSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + tdSuffix -> td
|
||||||
|
numSuffix = []byte("n") // headerPrefix + num (uint64 big endian) + numSuffix -> hash
|
||||||
|
blockHashPrefix = []byte("H") // blockHashPrefix + hash -> num (uint64 big endian)
|
||||||
|
bodyPrefix = []byte("b") // bodyPrefix + num (uint64 big endian) + hash -> block body
|
||||||
|
blockReceiptsPrefix = []byte("r") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
||||||
|
lookupPrefix = []byte("l") // lookupPrefix + hash -> transaction/receipt lookup metadata
|
||||||
|
bloomBitsPrefix = []byte("B") // bloomBitsPrefix + bit (uint16 big endian) + section (uint64 big endian) + hash -> bloom bits
|
||||||
|
|
||||||
|
preimagePrefix = "secure-key-" // preimagePrefix + hash -> preimage
|
||||||
|
configPrefix = []byte("ethereum-config-") // config prefix for the db
|
||||||
|
|
||||||
|
// Chain index prefixes (use `i` + single byte to avoid mixing data types).
|
||||||
|
BloomBitsIndexPrefix = []byte("iB") // BloomBitsIndexPrefix is the data table of a chain indexer to track its progress
|
||||||
|
|
||||||
|
// used by old db, now only used for conversion
|
||||||
|
oldReceiptsPrefix = []byte("receipts-")
|
||||||
|
oldTxMetaSuffix = []byte{0x01}
|
||||||
|
|
||||||
|
ErrChainConfigNotFound = errors.New("ChainConfig not found") // general config not found error
|
||||||
|
|
||||||
|
preimageCounter = metrics.NewCounter()
|
||||||
|
preimageHitCounter = metrics.NewCounter()
|
||||||
|
|
||||||
|
privateRootPrefix = []byte("P")
|
||||||
|
privateblockReceiptsPrefix = []byte("Pr") // blockReceiptsPrefix + num (uint64 big endian) + hash -> block receipts
|
||||||
|
privateReceiptPrefix = []byte("Prs")
|
||||||
|
privateBloomPrefix = []byte("Pb")
|
||||||
|
)
|
||||||
|
|
||||||
|
// txLookupEntry is a positional metadata to help looking up the data content of
|
||||||
|
// a transaction or receipt given only its hash.
|
||||||
|
type txLookupEntry struct {
|
||||||
|
BlockHash common.Hash
|
||||||
|
BlockIndex uint64
|
||||||
|
Index uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
// encodeBlockNumber encodes a block number as big endian uint64
|
||||||
|
func encodeBlockNumber(number uint64) []byte {
|
||||||
|
enc := make([]byte, 8)
|
||||||
|
binary.BigEndian.PutUint64(enc, number)
|
||||||
|
return enc
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCanonicalHash retrieves a hash assigned to a canonical block number.
|
||||||
|
func GetCanonicalHash(db DatabaseReader, number uint64) common.Hash {
|
||||||
|
data, _ := db.Get(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return common.BytesToHash(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// missingNumber is returned by GetBlockNumber if no header with the
|
||||||
|
// given block hash has been stored in the database
|
||||||
|
const missingNumber = uint64(0xffffffffffffffff)
|
||||||
|
|
||||||
|
// GetBlockNumber returns the block number assigned to a block hash
|
||||||
|
// if the corresponding header is present in the database
|
||||||
|
func GetBlockNumber(db DatabaseReader, hash common.Hash) uint64 {
|
||||||
|
data, _ := db.Get(append(blockHashPrefix, hash.Bytes()...))
|
||||||
|
if len(data) != 8 {
|
||||||
|
return missingNumber
|
||||||
|
}
|
||||||
|
return binary.BigEndian.Uint64(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeadHeaderHash retrieves the hash of the current canonical head block's
|
||||||
|
// header. The difference between this and GetHeadBlockHash is that whereas the
|
||||||
|
// last block hash is only updated upon a full block import, the last header
|
||||||
|
// hash is updated already at header import, allowing head tracking for the
|
||||||
|
// light synchronization mechanism.
|
||||||
|
func GetHeadHeaderHash(db DatabaseReader) common.Hash {
|
||||||
|
data, _ := db.Get(headHeaderKey)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return common.BytesToHash(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeadBlockHash retrieves the hash of the current canonical head block.
|
||||||
|
func GetHeadBlockHash(db DatabaseReader) common.Hash {
|
||||||
|
data, _ := db.Get(headBlockKey)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return common.BytesToHash(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeadFastBlockHash retrieves the hash of the current canonical head block during
|
||||||
|
// fast synchronization. The difference between this and GetHeadBlockHash is that
|
||||||
|
// whereas the last block hash is only updated upon a full block import, the last
|
||||||
|
// fast hash is updated when importing pre-processed blocks.
|
||||||
|
func GetHeadFastBlockHash(db DatabaseReader) common.Hash {
|
||||||
|
data, _ := db.Get(headFastKey)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return common.Hash{}
|
||||||
|
}
|
||||||
|
return common.BytesToHash(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeaderRLP retrieves a block header in its raw RLP database encoding, or nil
|
||||||
|
// if the header's not found.
|
||||||
|
func GetHeaderRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
|
data, _ := db.Get(headerKey(hash, number))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHeader retrieves the block header corresponding to the hash, nil if none
|
||||||
|
// found.
|
||||||
|
func GetHeader(db DatabaseReader, hash common.Hash, number uint64) *types.Header {
|
||||||
|
data := GetHeaderRLP(db, hash, number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
header := new(types.Header)
|
||||||
|
if err := rlp.Decode(bytes.NewReader(data), header); err != nil {
|
||||||
|
log.Error("Invalid block header RLP", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return header
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBodyRLP retrieves the block body (transactions and uncles) in RLP encoding.
|
||||||
|
func GetBodyRLP(db DatabaseReader, hash common.Hash, number uint64) rlp.RawValue {
|
||||||
|
data, _ := db.Get(blockBodyKey(hash, number))
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func headerKey(hash common.Hash, number uint64) []byte {
|
||||||
|
return append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func blockBodyKey(hash common.Hash, number uint64) []byte {
|
||||||
|
return append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBody retrieves the block body (transactons, uncles) corresponding to the
|
||||||
|
// hash, nil if none found.
|
||||||
|
func GetBody(db DatabaseReader, hash common.Hash, number uint64) *types.Body {
|
||||||
|
data := GetBodyRLP(db, hash, number)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
body := new(types.Body)
|
||||||
|
if err := rlp.Decode(bytes.NewReader(data), body); err != nil {
|
||||||
|
log.Error("Invalid block body RLP", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTd retrieves a block's total difficulty corresponding to the hash, nil if
|
||||||
|
// none found.
|
||||||
|
func GetTd(db DatabaseReader, hash common.Hash, number uint64) *big.Int {
|
||||||
|
data, _ := db.Get(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash[:]...), tdSuffix...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
td := new(big.Int)
|
||||||
|
if err := rlp.Decode(bytes.NewReader(data), td); err != nil {
|
||||||
|
log.Error("Invalid block total difficulty RLP", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return td
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlock retrieves an entire block corresponding to the hash, assembling it
|
||||||
|
// back from the stored header and body. If either the header or body could not
|
||||||
|
// be retrieved nil is returned.
|
||||||
|
//
|
||||||
|
// Note, due to concurrent download of header and block body the header and thus
|
||||||
|
// canonical hash can be stored in the database but the body data not (yet).
|
||||||
|
func GetBlock(db DatabaseReader, hash common.Hash, number uint64) *types.Block {
|
||||||
|
// Retrieve the block header and body contents
|
||||||
|
header := GetHeader(db, hash, number)
|
||||||
|
if header == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
body := GetBody(db, hash, number)
|
||||||
|
if body == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// Reassemble the block and return
|
||||||
|
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockReceipts retrieves the receipts generated by the transactions included
|
||||||
|
// in a block given by its hash.
|
||||||
|
func GetBlockReceipts(db DatabaseReader, hash common.Hash, number uint64) types.Receipts {
|
||||||
|
data, _ := db.Get(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash[:]...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
storageReceipts := []*types.ReceiptForStorage{}
|
||||||
|
if err := rlp.DecodeBytes(data, &storageReceipts); err != nil {
|
||||||
|
log.Error("Invalid receipt array RLP", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
receipts := make(types.Receipts, len(storageReceipts))
|
||||||
|
for i, receipt := range storageReceipts {
|
||||||
|
receipts[i] = (*types.Receipt)(receipt)
|
||||||
|
}
|
||||||
|
return receipts
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTxLookupEntry retrieves the positional metadata associated with a transaction
|
||||||
|
// hash to allow retrieving the transaction or receipt by hash.
|
||||||
|
func GetTxLookupEntry(db DatabaseReader, hash common.Hash) (common.Hash, uint64, uint64) {
|
||||||
|
// Load the positional metadata from disk and bail if it fails
|
||||||
|
data, _ := db.Get(append(lookupPrefix, hash.Bytes()...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
// Parse and return the contents of the lookup entry
|
||||||
|
var entry txLookupEntry
|
||||||
|
if err := rlp.DecodeBytes(data, &entry); err != nil {
|
||||||
|
log.Error("Invalid lookup entry RLP", "hash", hash, "err", err)
|
||||||
|
return common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
return entry.BlockHash, entry.BlockIndex, entry.Index
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTransaction retrieves a specific transaction from the database, along with
|
||||||
|
// its added positional metadata.
|
||||||
|
func GetTransaction(db DatabaseReader, hash common.Hash) (*types.Transaction, common.Hash, uint64, uint64) {
|
||||||
|
// Retrieve the lookup metadata and resolve the transaction from the body
|
||||||
|
blockHash, blockNumber, txIndex := GetTxLookupEntry(db, hash)
|
||||||
|
|
||||||
|
if blockHash != (common.Hash{}) {
|
||||||
|
body := GetBody(db, blockHash, blockNumber)
|
||||||
|
if body == nil || len(body.Transactions) <= int(txIndex) {
|
||||||
|
log.Error("Transaction referenced missing", "number", blockNumber, "hash", blockHash, "index", txIndex)
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
return body.Transactions[txIndex], blockHash, blockNumber, txIndex
|
||||||
|
}
|
||||||
|
// Old transaction representation, load the transaction and it's metadata separately
|
||||||
|
data, _ := db.Get(hash.Bytes())
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
var tx types.Transaction
|
||||||
|
if err := rlp.DecodeBytes(data, &tx); err != nil {
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
// Retrieve the blockchain positional metadata
|
||||||
|
data, _ = db.Get(append(hash.Bytes(), oldTxMetaSuffix...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
var entry txLookupEntry
|
||||||
|
if err := rlp.DecodeBytes(data, &entry); err != nil {
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
return &tx, entry.BlockHash, entry.BlockIndex, entry.Index
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetReceipt retrieves a specific transaction receipt from the database, along with
|
||||||
|
// its added positional metadata.
|
||||||
|
func GetReceipt(db DatabaseReader, hash common.Hash) (*types.Receipt, common.Hash, uint64, uint64) {
|
||||||
|
// Retrieve the lookup metadata and resolve the receipt from the receipts
|
||||||
|
blockHash, blockNumber, receiptIndex := GetTxLookupEntry(db, hash)
|
||||||
|
|
||||||
|
if blockHash != (common.Hash{}) {
|
||||||
|
receipts := GetBlockReceipts(db, blockHash, blockNumber)
|
||||||
|
if len(receipts) <= int(receiptIndex) {
|
||||||
|
log.Error("Receipt refereced missing", "number", blockNumber, "hash", blockHash, "index", receiptIndex)
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
return receipts[receiptIndex], blockHash, blockNumber, receiptIndex
|
||||||
|
}
|
||||||
|
// Old receipt representation, load the receipt and set an unknown metadata
|
||||||
|
data, _ := db.Get(append(oldReceiptsPrefix, hash[:]...))
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil, common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
var receipt types.ReceiptForStorage
|
||||||
|
err := rlp.DecodeBytes(data, &receipt)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Invalid receipt RLP", "hash", hash, "err", err)
|
||||||
|
}
|
||||||
|
return (*types.Receipt)(&receipt), common.Hash{}, 0, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBloomBits retrieves the compressed bloom bit vector belonging to the given
|
||||||
|
// section and bit index from the.
|
||||||
|
func GetBloomBits(db DatabaseReader, bit uint, section uint64, head common.Hash) []byte {
|
||||||
|
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(key[1:], uint16(bit))
|
||||||
|
binary.BigEndian.PutUint64(key[3:], section)
|
||||||
|
|
||||||
|
bits, _ := db.Get(key)
|
||||||
|
return bits
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteCanonicalHash stores the canonical hash for the given block number.
|
||||||
|
func WriteCanonicalHash(db ethdb.Putter, hash common.Hash, number uint64) error {
|
||||||
|
key := append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...)
|
||||||
|
if err := db.Put(key, hash.Bytes()); err != nil {
|
||||||
|
log.Crit("Failed to store number to hash mapping", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeadHeaderHash stores the head header's hash.
|
||||||
|
func WriteHeadHeaderHash(db ethdb.Putter, hash common.Hash) error {
|
||||||
|
if err := db.Put(headHeaderKey, hash.Bytes()); err != nil {
|
||||||
|
log.Crit("Failed to store last header's hash", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeadBlockHash stores the head block's hash.
|
||||||
|
func WriteHeadBlockHash(db ethdb.Putter, hash common.Hash) error {
|
||||||
|
if err := db.Put(headBlockKey, hash.Bytes()); err != nil {
|
||||||
|
log.Crit("Failed to store last block's hash", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeadFastBlockHash stores the fast head block's hash.
|
||||||
|
func WriteHeadFastBlockHash(db ethdb.Putter, hash common.Hash) error {
|
||||||
|
if err := db.Put(headFastKey, hash.Bytes()); err != nil {
|
||||||
|
log.Crit("Failed to store last fast block's hash", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteHeader serializes a block header into the database.
|
||||||
|
func WriteHeader(db ethdb.Putter, header *types.Header) error {
|
||||||
|
data, err := rlp.EncodeToBytes(header)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
hash := header.Hash().Bytes()
|
||||||
|
num := header.Number.Uint64()
|
||||||
|
encNum := encodeBlockNumber(num)
|
||||||
|
key := append(blockHashPrefix, hash...)
|
||||||
|
if err := db.Put(key, encNum); err != nil {
|
||||||
|
log.Crit("Failed to store hash to number mapping", "err", err)
|
||||||
|
}
|
||||||
|
key = append(append(headerPrefix, encNum...), hash...)
|
||||||
|
if err := db.Put(key, data); err != nil {
|
||||||
|
log.Crit("Failed to store header", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBody serializes the body of a block into the database.
|
||||||
|
func WriteBody(db ethdb.Putter, hash common.Hash, number uint64, body *types.Body) error {
|
||||||
|
data, err := rlp.EncodeToBytes(body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return WriteBodyRLP(db, hash, number, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBodyRLP writes a serialized body of a block into the database.
|
||||||
|
func WriteBodyRLP(db ethdb.Putter, hash common.Hash, number uint64, rlp rlp.RawValue) error {
|
||||||
|
key := append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
if err := db.Put(key, rlp); err != nil {
|
||||||
|
log.Crit("Failed to store block body", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTd serializes the total difficulty of a block into the database.
|
||||||
|
func WriteTd(db ethdb.Putter, hash common.Hash, number uint64, td *big.Int) error {
|
||||||
|
data, err := rlp.EncodeToBytes(td)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
key := append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...)
|
||||||
|
if err := db.Put(key, data); err != nil {
|
||||||
|
log.Crit("Failed to store block total difficulty", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBlock serializes a block into the database, header and body separately.
|
||||||
|
func WriteBlock(db ethdb.Putter, block *types.Block) error {
|
||||||
|
// Store the body first to retain database consistency
|
||||||
|
if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Store the header too, signaling full block ownership
|
||||||
|
if err := WriteHeader(db, block.Header()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBlockReceipts stores all the transaction receipts belonging to a block
|
||||||
|
// as a single receipt slice. This is used during chain reorganisations for
|
||||||
|
// rescheduling dropped transactions.
|
||||||
|
func WriteBlockReceipts(db ethdb.Putter, hash common.Hash, number uint64, receipts types.Receipts) error {
|
||||||
|
// Convert the receipts into their storage form and serialize them
|
||||||
|
storageReceipts := make([]*types.ReceiptForStorage, len(receipts))
|
||||||
|
for i, receipt := range receipts {
|
||||||
|
storageReceipts[i] = (*types.ReceiptForStorage)(receipt)
|
||||||
|
}
|
||||||
|
bytes, err := rlp.EncodeToBytes(storageReceipts)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Store the flattened receipt slice
|
||||||
|
key := append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...)
|
||||||
|
if err := db.Put(key, bytes); err != nil {
|
||||||
|
log.Crit("Failed to store block receipts", "err", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteTxLookupEntries stores a positional metadata for every transaction from
|
||||||
|
// a block, enabling hash based transaction and receipt lookups.
|
||||||
|
func WriteTxLookupEntries(db ethdb.Putter, block *types.Block) error {
|
||||||
|
// Iterate over each transaction and encode its metadata
|
||||||
|
for i, tx := range block.Transactions() {
|
||||||
|
entry := txLookupEntry{
|
||||||
|
BlockHash: block.Hash(),
|
||||||
|
BlockIndex: block.NumberU64(),
|
||||||
|
Index: uint64(i),
|
||||||
|
}
|
||||||
|
data, err := rlp.EncodeToBytes(entry)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := db.Put(append(lookupPrefix, tx.Hash().Bytes()...), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBloomBits writes the compressed bloom bits vector belonging to the given
|
||||||
|
// section and bit index.
|
||||||
|
func WriteBloomBits(db ethdb.Putter, bit uint, section uint64, head common.Hash, bits []byte) {
|
||||||
|
key := append(append(bloomBitsPrefix, make([]byte, 10)...), head.Bytes()...)
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteCanonicalHash removes the number to hash canonical mapping.
|
||||||
|
func DeleteCanonicalHash(db DatabaseDeleter, number uint64) {
|
||||||
|
db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), numSuffix...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteHeader removes all block header data associated with a hash.
|
||||||
|
func DeleteHeader(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||||
|
db.Delete(append(blockHashPrefix, hash.Bytes()...))
|
||||||
|
db.Delete(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBody removes all block body data associated with a hash.
|
||||||
|
func DeleteBody(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||||
|
db.Delete(append(append(bodyPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTd removes all block total difficulty data associated with a hash.
|
||||||
|
func DeleteTd(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||||
|
db.Delete(append(append(append(headerPrefix, encodeBlockNumber(number)...), hash.Bytes()...), tdSuffix...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBlock removes all block data associated with a hash.
|
||||||
|
func DeleteBlock(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||||
|
DeleteBlockReceipts(db, hash, number)
|
||||||
|
DeleteHeader(db, hash, number)
|
||||||
|
DeleteBody(db, hash, number)
|
||||||
|
DeleteTd(db, hash, number)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteBlockReceipts removes all receipt data associated with a block hash.
|
||||||
|
func DeleteBlockReceipts(db DatabaseDeleter, hash common.Hash, number uint64) {
|
||||||
|
db.Delete(append(append(blockReceiptsPrefix, encodeBlockNumber(number)...), hash.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
||||||
|
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
|
||||||
|
db.Delete(append(lookupPrefix, hash.Bytes()...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PreimageTable returns a Database instance with the key prefix for preimage entries.
|
||||||
|
func PreimageTable(db ethdb.Database) ethdb.Database {
|
||||||
|
return ethdb.NewTable(db, preimagePrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WritePreimages writes the provided set of preimages to the database. `number` is the
|
||||||
|
// current block number, and is used for debug messages only.
|
||||||
|
func WritePreimages(db ethdb.Database, number uint64, preimages map[common.Hash][]byte) error {
|
||||||
|
table := PreimageTable(db)
|
||||||
|
batch := table.NewBatch()
|
||||||
|
hitCount := 0
|
||||||
|
for hash, preimage := range preimages {
|
||||||
|
if _, err := table.Get(hash.Bytes()); err != nil {
|
||||||
|
batch.Put(hash.Bytes(), preimage)
|
||||||
|
hitCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
preimageCounter.Inc(int64(len(preimages)))
|
||||||
|
preimageHitCounter.Inc(int64(hitCount))
|
||||||
|
if hitCount > 0 {
|
||||||
|
if err := batch.Write(); err != nil {
|
||||||
|
return fmt.Errorf("preimage write fail for block %d: %v", number, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBlockChainVersion reads the version number from db.
|
||||||
|
func GetBlockChainVersion(db DatabaseReader) int {
|
||||||
|
var vsn uint
|
||||||
|
enc, _ := db.Get([]byte("BlockchainVersion"))
|
||||||
|
rlp.DecodeBytes(enc, &vsn)
|
||||||
|
return int(vsn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteBlockChainVersion writes vsn as the version number to db.
|
||||||
|
func WriteBlockChainVersion(db ethdb.Putter, vsn int) {
|
||||||
|
enc, _ := rlp.EncodeToBytes(uint(vsn))
|
||||||
|
db.Put([]byte("BlockchainVersion"), enc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteChainConfig writes the chain config settings to the database.
|
||||||
|
func WriteChainConfig(db ethdb.Putter, hash common.Hash, cfg *params.ChainConfig) error {
|
||||||
|
// short circuit and ignore if nil config. GetChainConfig
|
||||||
|
// will return a default.
|
||||||
|
if cfg == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonChainConfig, err := json.Marshal(cfg)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.Put(append(configPrefix, hash[:]...), jsonChainConfig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChainConfig will fetch the network settings based on the given hash.
|
||||||
|
func GetChainConfig(db DatabaseReader, hash common.Hash) (*params.ChainConfig, error) {
|
||||||
|
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
|
||||||
|
if len(jsonChainConfig) == 0 {
|
||||||
|
return nil, ErrChainConfigNotFound
|
||||||
|
}
|
||||||
|
|
||||||
|
var config params.ChainConfig
|
||||||
|
if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// FindCommonAncestor returns the last common ancestor of two block headers
|
||||||
|
func FindCommonAncestor(db DatabaseReader, a, b *types.Header) *types.Header {
|
||||||
|
for bn := b.Number.Uint64(); a.Number.Uint64() > bn; {
|
||||||
|
a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for an := a.Number.Uint64(); an < b.Number.Uint64(); {
|
||||||
|
b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1)
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for a.Hash() != b.Hash() {
|
||||||
|
a = GetHeader(db, a.ParentHash, a.Number.Uint64()-1)
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
b = GetHeader(db, b.ParentHash, b.Number.Uint64()-1)
|
||||||
|
if b == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetPrivateStateRoot(db ethdb.Database, blockRoot common.Hash) common.Hash {
|
||||||
|
root, _ := db.Get(append(privateRootPrefix, blockRoot[:]...))
|
||||||
|
return common.BytesToHash(root)
|
||||||
|
}
|
||||||
|
|
||||||
|
func WritePrivateStateRoot(db ethdb.Database, blockRoot, root common.Hash) error {
|
||||||
|
return db.Put(append(privateRootPrefix, blockRoot[:]...), root[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// WritePrivateBlockBloom creates a bloom filter for the given receipts and saves it to the database
|
||||||
|
// with the number given as identifier (i.e. block number).
|
||||||
|
func WritePrivateBlockBloom(db ethdb.Database, number uint64, receipts types.Receipts) error {
|
||||||
|
rbloom := types.CreateBloom(receipts)
|
||||||
|
return db.Put(append(privateBloomPrefix, encodeBlockNumber(number)...), rbloom[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrivateBlockBloom retrieves the private bloom associated with the given number.
|
||||||
|
func GetPrivateBlockBloom(db ethdb.Database, number uint64) (bloom types.Bloom) {
|
||||||
|
data, _ := db.Get(append(privateBloomPrefix, encodeBlockNumber(number)...))
|
||||||
|
if len(data) > 0 {
|
||||||
|
bloom = types.BytesToBloom(data)
|
||||||
|
}
|
||||||
|
return bloom
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ const (
|
||||||
type blockChain interface {
|
type blockChain interface {
|
||||||
CurrentBlock() *types.Block
|
CurrentBlock() *types.Block
|
||||||
GetBlock(hash common.Hash, number uint64) *types.Block
|
GetBlock(hash common.Hash, number uint64) *types.Block
|
||||||
StateAt(root common.Hash) (*state.StateDB, error)
|
StateAt(root common.Hash) (*state.StateDB, *state.StateDB, error)
|
||||||
|
|
||||||
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
|
SubscribeChainHeadEvent(ch chan<- ChainHeadEvent) event.Subscription
|
||||||
}
|
}
|
||||||
|
@ -240,7 +240,7 @@ func NewTxPool(config TxPoolConfig, chainconfig *params.ChainConfig, chain block
|
||||||
if !config.NoLocals && config.Journal != "" {
|
if !config.NoLocals && config.Journal != "" {
|
||||||
pool.journal = newTxJournal(config.Journal)
|
pool.journal = newTxJournal(config.Journal)
|
||||||
|
|
||||||
if err := pool.journal.load(pool.AddLocal); err != nil {
|
if err := pool.journal.load(pool.AddLocals); err != nil {
|
||||||
log.Warn("Failed to load transaction journal", "err", err)
|
log.Warn("Failed to load transaction journal", "err", err)
|
||||||
}
|
}
|
||||||
if err := pool.journal.rotate(pool.local()); err != nil {
|
if err := pool.journal.rotate(pool.local()); err != nil {
|
||||||
|
@ -402,7 +402,7 @@ func (pool *TxPool) reset(oldHead, newHead *types.Header) {
|
||||||
if newHead == nil {
|
if newHead == nil {
|
||||||
newHead = pool.chain.CurrentBlock().Header() // Special case during testing
|
newHead = pool.chain.CurrentBlock().Header() // Special case during testing
|
||||||
}
|
}
|
||||||
statedb, err := pool.chain.StateAt(newHead.Root)
|
statedb, _, err := pool.chain.StateAt(newHead.Root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error("Failed to reset txpool state", "err", err)
|
log.Error("Failed to reset txpool state", "err", err)
|
||||||
return
|
return
|
||||||
|
@ -624,7 +624,7 @@ func (pool *TxPool) add(tx *types.Transaction, local bool) (bool, error) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
// If the transaction pool is full, discard underpriced transactions
|
// If the transaction pool is full, discard underpriced transactions
|
||||||
if uint64(len(pool.all)) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
|
if uint64(pool.all.Count()) >= pool.config.GlobalSlots+pool.config.GlobalQueue {
|
||||||
// If the new transaction is underpriced, don't accept it
|
// If the new transaction is underpriced, don't accept it
|
||||||
if !pool.chainconfig.IsQuorum && !local && pool.priced.Underpriced(tx, pool.locals) {
|
if !pool.chainconfig.IsQuorum && !local && pool.priced.Underpriced(tx, pool.locals) {
|
||||||
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
|
log.Trace("Discarding underpriced transaction", "hash", hash, "price", tx.GasPrice())
|
||||||
|
|
|
@ -95,7 +95,7 @@ func validateTxPoolInternals(pool *TxPool) error {
|
||||||
|
|
||||||
// Ensure the total transaction set is consistent with pending + queued
|
// Ensure the total transaction set is consistent with pending + queued
|
||||||
pending, queued := pool.stats()
|
pending, queued := pool.stats()
|
||||||
if total := len(pool.all); total != pending+queued {
|
if total := pool.all.Count(); total != pending+queued {
|
||||||
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
|
return fmt.Errorf("total transaction count %d != %d pending + %d queued", total, pending, queued)
|
||||||
}
|
}
|
||||||
if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued {
|
if priced := pool.priced.items.Len() - pool.priced.stales; priced != pending+queued {
|
||||||
|
@ -119,7 +119,7 @@ func validateTxPoolInternals(pool *TxPool) error {
|
||||||
|
|
||||||
// validateEvents checks that the correct number of transaction addition events
|
// validateEvents checks that the correct number of transaction addition events
|
||||||
// were fired on the pool's event feed.
|
// were fired on the pool's event feed.
|
||||||
func validateEvents(events chan TxPreEvent, count int) error {
|
func validateEvents(events chan NewTxsEvent, count int) error {
|
||||||
for i := 0; i < count; i++ {
|
for i := 0; i < count; i++ {
|
||||||
select {
|
select {
|
||||||
case <-events:
|
case <-events:
|
||||||
|
@ -129,7 +129,7 @@ func validateEvents(events chan TxPreEvent, count int) error {
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case tx := <-events:
|
case tx := <-events:
|
||||||
return fmt.Errorf("more than %d events fired: %v", count, tx.Tx)
|
return fmt.Errorf("more than %d events fired: %v", count, tx.Txs)
|
||||||
|
|
||||||
case <-time.After(50 * time.Millisecond):
|
case <-time.After(50 * time.Millisecond):
|
||||||
// This branch should be "default", but it's a data race between goroutines,
|
// This branch should be "default", but it's a data race between goroutines,
|
||||||
|
@ -484,7 +484,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
|
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
|
||||||
}
|
}
|
||||||
if pool.all.Count() != 6 {
|
if pool.all.Count() != 6 {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6)
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6)
|
||||||
}
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
if pool.pending[account].Len() != 3 {
|
if pool.pending[account].Len() != 3 {
|
||||||
|
@ -494,7 +494,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
|
t.Errorf("queued transaction mismatch: have %d, want %d", pool.queue[account].Len(), 3)
|
||||||
}
|
}
|
||||||
if pool.all.Count() != 6 {
|
if pool.all.Count() != 6 {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), 6)
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), 6)
|
||||||
}
|
}
|
||||||
// Reduce the balance of the account, and check that invalidated transactions are dropped
|
// Reduce the balance of the account, and check that invalidated transactions are dropped
|
||||||
pool.currentState.AddBalance(account, big.NewInt(-650))
|
pool.currentState.AddBalance(account, big.NewInt(-650))
|
||||||
|
@ -611,7 +611,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||||
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if pool.all.Count() != len(txs) {
|
if pool.all.Count() != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs))
|
||||||
}
|
}
|
||||||
pool.lockedReset(nil, nil)
|
pool.lockedReset(nil, nil)
|
||||||
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
if pending := pool.pending[accs[0]].Len() + pool.pending[accs[1]].Len(); pending != len(txs) {
|
||||||
|
@ -621,7 +621,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||||
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
t.Errorf("queued accounts mismatch: have %d, want %d", len(pool.queue), 0)
|
||||||
}
|
}
|
||||||
if pool.all.Count() != len(txs) {
|
if pool.all.Count() != len(txs) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs))
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs))
|
||||||
}
|
}
|
||||||
// Reduce the balance of the account, and check that transactions are reorganised
|
// Reduce the balance of the account, and check that transactions are reorganised
|
||||||
for _, addr := range accs {
|
for _, addr := range accs {
|
||||||
|
@ -671,7 +671,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pool.all.Count() != len(txs)/2 {
|
if pool.all.Count() != len(txs)/2 {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), len(txs)/2)
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), len(txs)/2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -763,7 +763,7 @@ func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pool.all.Count() != int(testTxPoolConfig.AccountQueue) {
|
if pool.all.Count() != int(testTxPoolConfig.AccountQueue) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue)
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,7 +957,7 @@ func TestTransactionPendingLimiting(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if pool.all.Count() != int(testTxPoolConfig.AccountQueue+5) {
|
if pool.all.Count() != int(testTxPoolConfig.AccountQueue+5) {
|
||||||
t.Errorf("total transaction mismatch: have %d, want %d", len(pool.all), testTxPoolConfig.AccountQueue+5)
|
t.Errorf("total transaction mismatch: have %d, want %d", pool.all.Count(), testTxPoolConfig.AccountQueue+5)
|
||||||
}
|
}
|
||||||
if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil {
|
if err := validateEvents(events, int(testTxPoolConfig.AccountQueue+5)); err != nil {
|
||||||
t.Fatalf("event firing failed: %v", err)
|
t.Fatalf("event firing failed: %v", err)
|
||||||
|
|
|
@ -42,5 +42,5 @@ type Validator interface {
|
||||||
// of gas used in the process and return an error if any of the internal rules
|
// of gas used in the process and return an error if any of the internal rules
|
||||||
// failed.
|
// failed.
|
||||||
type Processor interface {
|
type Processor interface {
|
||||||
Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, uint64, error)
|
Process(block *types.Block, statedb, privateState *state.StateDB, cfg vm.Config) (types.Receipts, types.Receipts, []*types.Log, uint64, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
fmt "fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
|
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
|
||||||
|
|
|
@ -32,7 +32,7 @@ type twoOperandTest struct {
|
||||||
|
|
||||||
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error)) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
pc = uint64(0)
|
pc = uint64(0)
|
||||||
)
|
)
|
||||||
|
@ -70,7 +70,7 @@ func testTwoOperandOp(t *testing.T, tests []twoOperandTest, opFn func(pc *uint64
|
||||||
|
|
||||||
func TestByteOp(t *testing.T) {
|
func TestByteOp(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
)
|
)
|
||||||
env.interpreter.intPool = poolOfIntPools.get()
|
env.interpreter.intPool = poolOfIntPools.get()
|
||||||
|
@ -202,7 +202,7 @@ func TestSLT(t *testing.T) {
|
||||||
|
|
||||||
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
func opBenchmark(bench *testing.B, op func(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack) ([]byte, error), args ...string) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
)
|
)
|
||||||
// convert args
|
// convert args
|
||||||
|
@ -432,7 +432,7 @@ func BenchmarkOpIsZero(b *testing.B) {
|
||||||
|
|
||||||
func TestOpMstore(t *testing.T) {
|
func TestOpMstore(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
)
|
)
|
||||||
|
@ -455,7 +455,7 @@ func TestOpMstore(t *testing.T) {
|
||||||
|
|
||||||
func BenchmarkOpMstore(bench *testing.B) {
|
func BenchmarkOpMstore(bench *testing.B) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,26 +23,36 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Quorum uses a cut-down StateDB, MinimalApiState. We leave the methods in StateDB commented out so they'll produce a
|
||||||
|
// conflict when upstream changes.
|
||||||
|
type MinimalApiState interface {
|
||||||
|
GetBalance(addr common.Address) *big.Int
|
||||||
|
GetCode(addr common.Address) []byte
|
||||||
|
GetState(a common.Address, b common.Hash) common.Hash
|
||||||
|
GetNonce(addr common.Address) uint64
|
||||||
|
}
|
||||||
|
|
||||||
// StateDB is an EVM database for full state querying.
|
// StateDB is an EVM database for full state querying.
|
||||||
type StateDB interface {
|
type StateDB interface {
|
||||||
|
MinimalApiState
|
||||||
CreateAccount(common.Address)
|
CreateAccount(common.Address)
|
||||||
|
|
||||||
SubBalance(common.Address, *big.Int)
|
SubBalance(common.Address, *big.Int)
|
||||||
AddBalance(common.Address, *big.Int)
|
AddBalance(common.Address, *big.Int)
|
||||||
GetBalance(common.Address) *big.Int
|
//GetBalance(common.Address) *big.Int
|
||||||
|
|
||||||
GetNonce(common.Address) uint64
|
//GetNonce(common.Address) uint64
|
||||||
SetNonce(common.Address, uint64)
|
SetNonce(common.Address, uint64)
|
||||||
|
|
||||||
GetCodeHash(common.Address) common.Hash
|
GetCodeHash(common.Address) common.Hash
|
||||||
GetCode(common.Address) []byte
|
//GetCode(common.Address) []byte
|
||||||
SetCode(common.Address, []byte)
|
SetCode(common.Address, []byte)
|
||||||
GetCodeSize(common.Address) int
|
GetCodeSize(common.Address) int
|
||||||
|
|
||||||
AddRefund(uint64)
|
AddRefund(uint64)
|
||||||
GetRefund() uint64
|
GetRefund() uint64
|
||||||
|
|
||||||
GetState(common.Address, common.Hash) common.Hash
|
//GetState(common.Address, common.Hash) common.Hash
|
||||||
SetState(common.Address, common.Hash, common.Hash)
|
SetState(common.Address, common.Hash, common.Hash)
|
||||||
|
|
||||||
Suicide(common.Address) bool
|
Suicide(common.Address) bool
|
||||||
|
|
|
@ -48,7 +48,7 @@ type dummyStateDB struct {
|
||||||
|
|
||||||
func TestStoreCapture(t *testing.T) {
|
func TestStoreCapture(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
env = NewEVM(Context{}, nil, params.TestChainConfig, Config{})
|
env = NewEVM(Context{}, nil, nil, params.TestChainConfig, Config{})
|
||||||
logger = NewStructLogger(nil)
|
logger = NewStructLogger(nil)
|
||||||
mem = NewMemory()
|
mem = NewMemory()
|
||||||
stack = newstack()
|
stack = newstack()
|
||||||
|
|
|
@ -532,3 +532,13 @@ var stringToOp = map[string]OpCode{
|
||||||
func StringToOp(str string) OpCode {
|
func StringToOp(str string) OpCode {
|
||||||
return stringToOp[str]
|
return stringToOp[str]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (op OpCode) isMutating() bool {
|
||||||
|
switch op {
|
||||||
|
// TODO(joel): REVERT?
|
||||||
|
case SELFDESTRUCT, CREATE, SSTORE, LOG0, LOG1, LOG2, LOG3, LOG4:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
42
eth/api.go
42
eth/api.go
|
@ -307,28 +307,38 @@ func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
// DumpBlock retrieves the entire state of the database at a given block.
|
// DumpBlock retrieves the entire state of the database at a given block.
|
||||||
func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber) (state.Dump, error) {
|
func (api *PublicDebugAPI) DumpBlock(blockNr rpc.BlockNumber, typ string) (state.Dump, error) {
|
||||||
|
var publicState, privateState *state.StateDB
|
||||||
|
var err error
|
||||||
if blockNr == rpc.PendingBlockNumber {
|
if blockNr == rpc.PendingBlockNumber {
|
||||||
// If we're dumping the pending state, we need to request
|
// If we're dumping the pending state, we need to request
|
||||||
// both the pending block as well as the pending state from
|
// both the pending block as well as the pending state from
|
||||||
// the miner and operate on those
|
// the miner and operate on those
|
||||||
_, stateDb := api.eth.miner.Pending()
|
_, publicState, privateState = api.eth.miner.Pending()
|
||||||
return stateDb.RawDump(), nil
|
|
||||||
}
|
|
||||||
var block *types.Block
|
|
||||||
if blockNr == rpc.LatestBlockNumber {
|
|
||||||
block = api.eth.blockchain.CurrentBlock()
|
|
||||||
} else {
|
} else {
|
||||||
block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
var block *types.Block
|
||||||
|
if blockNr == rpc.LatestBlockNumber {
|
||||||
|
block = api.eth.blockchain.CurrentBlock()
|
||||||
|
} else {
|
||||||
|
block = api.eth.blockchain.GetBlockByNumber(uint64(blockNr))
|
||||||
|
}
|
||||||
|
if block == nil {
|
||||||
|
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
||||||
|
}
|
||||||
|
publicState, privateState, err = api.eth.BlockChain().StateAt(block.Root())
|
||||||
|
if err != nil {
|
||||||
|
return state.Dump{}, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if block == nil {
|
|
||||||
return state.Dump{}, fmt.Errorf("block #%d not found", blockNr)
|
switch typ {
|
||||||
|
case "public":
|
||||||
|
return publicState.RawDump(), nil
|
||||||
|
case "private":
|
||||||
|
return privateState.RawDump(), nil
|
||||||
|
default:
|
||||||
|
return state.Dump{}, fmt.Errorf("unknown type: '%s'", typ)
|
||||||
}
|
}
|
||||||
stateDb, err := api.eth.BlockChain().StateAt(block.Root())
|
|
||||||
if err != nil {
|
|
||||||
return state.Dump{}, err
|
|
||||||
}
|
|
||||||
return stateDb.RawDump(), nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrivateDebugAPI is the collection of Ethereum full node APIs exposed over
|
// PrivateDebugAPI is the collection of Ethereum full node APIs exposed over
|
||||||
|
@ -397,7 +407,7 @@ type storageEntry struct {
|
||||||
|
|
||||||
// StorageRangeAt returns the storage at the given block height and transaction index.
|
// StorageRangeAt returns the storage at the given block height and transaction index.
|
||||||
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
|
func (api *PrivateDebugAPI) StorageRangeAt(ctx context.Context, blockHash common.Hash, txIndex int, contractAddress common.Address, keyStart hexutil.Bytes, maxResult int) (StorageRangeResult, error) {
|
||||||
_, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
|
_, _, _, statedb, err := api.computeTxEnv(blockHash, txIndex, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StorageRangeResult{}, err
|
return StorageRangeResult{}, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,8 +204,8 @@ func (b *EthAPIBackend) TxPoolContent() (map[common.Address]types.Transactions,
|
||||||
return b.eth.TxPool().Content()
|
return b.eth.TxPool().Content()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
func (b *EthAPIBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
|
||||||
return b.eth.TxPool().SubscribeTxPreEvent(ch)
|
return b.eth.TxPool().SubscribeNewTxsEvent(ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) Downloader() *downloader.Downloader {
|
func (b *EthAPIBackend) Downloader() *downloader.Downloader {
|
||||||
|
|
|
@ -238,13 +238,13 @@ func CreateConsensusEngine(ctx *node.ServiceContext, config *Config, chainConfig
|
||||||
|
|
||||||
// Otherwise assume proof-of-work
|
// Otherwise assume proof-of-work
|
||||||
switch config.PowMode {
|
switch config.PowMode {
|
||||||
case ethash.ModeFake:
|
case ModeFake:
|
||||||
log.Warn("Ethash used in fake mode")
|
log.Warn("Ethash used in fake mode")
|
||||||
return ethash.NewFaker()
|
return ethash.NewFaker()
|
||||||
case ethash.ModeTest:
|
case ModeTest:
|
||||||
log.Warn("Ethash used in test mode")
|
log.Warn("Ethash used in test mode")
|
||||||
return ethash.NewTester()
|
return ethash.NewTester()
|
||||||
case ethash.ModeShared:
|
case ModeShared:
|
||||||
log.Warn("Ethash used in shared mode")
|
log.Warn("Ethash used in shared mode")
|
||||||
return ethash.NewShared()
|
return ethash.NewShared()
|
||||||
default:
|
default:
|
||||||
|
|
|
@ -102,7 +102,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(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, networkID uint64, mux *event.TypeMux, txpool txPool, engine consensus.Engine, blockchain *core.BlockChain, chaindb ethdb.Database, raftMode bool) (*ProtocolManager, error) {
|
||||||
// Create the protocol manager with the base fields
|
// Create the protocol manager with the base fields
|
||||||
manager := &ProtocolManager{
|
manager := &ProtocolManager{
|
||||||
networkID: networkID,
|
networkID: networkID,
|
||||||
|
@ -239,7 +239,7 @@ func (pm *ProtocolManager) Start(maxPeers int) {
|
||||||
func (pm *ProtocolManager) Stop() {
|
func (pm *ProtocolManager) Stop() {
|
||||||
log.Info("Stopping Ethereum protocol")
|
log.Info("Stopping Ethereum protocol")
|
||||||
|
|
||||||
pm.txSub.Unsubscribe() // quits txBroadcastLoop
|
pm.txsSub.Unsubscribe() // quits txBroadcastLoop
|
||||||
if !pm.raftMode {
|
if !pm.raftMode {
|
||||||
pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
|
pm.minedBlockSub.Unsubscribe() // quits blockBroadcastLoop
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,17 +207,6 @@ func (*HandlerT) SetGCPercent(v int) int {
|
||||||
return debug.SetGCPercent(v)
|
return debug.SetGCPercent(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FreeOSMemory returns unused memory to the OS.
|
|
||||||
func (*HandlerT) FreeOSMemory() {
|
|
||||||
debug.FreeOSMemory()
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetGCPercent sets the garbage collection target percentage. It returns the previous
|
|
||||||
// setting. A negative value disables GC.
|
|
||||||
func (*HandlerT) SetGCPercent(v int) int {
|
|
||||||
return debug.SetGCPercent(v)
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeProfile(name, file string) error {
|
func writeProfile(name, file string) error {
|
||||||
p := pprof.Lookup(name)
|
p := pprof.Lookup(name)
|
||||||
log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file)
|
log.Info("Writing profile records", "count", p.Count(), "type", name, "dump", file)
|
||||||
|
|
|
@ -361,7 +361,7 @@ func (s *PrivateAccountAPI) signTransaction(ctx context.Context, args SendTxArgs
|
||||||
|
|
||||||
var chainID *big.Int
|
var chainID *big.Int
|
||||||
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
||||||
chainID = config.ChainId
|
chainID = config.ChainID
|
||||||
}
|
}
|
||||||
return wallet.SignTxWithPassphrase(account, passwd, tx, chainID)
|
return wallet.SignTxWithPassphrase(account, passwd, tx, chainID)
|
||||||
}
|
}
|
||||||
|
@ -521,7 +521,7 @@ func (s *PublicBlockChainAPI) GetBalance(ctx context.Context, address common.Add
|
||||||
if state == nil || err != nil {
|
if state == nil || err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return (*hexutil.Big)(state.GetBalance(address)), state.Error()
|
return (*hexutil.Big)(state.GetBalance(address)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -608,7 +608,7 @@ func (s *PublicBlockChainAPI) GetCode(ctx context.Context, address common.Addres
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
code := state.GetCode(address)
|
code := state.GetCode(address)
|
||||||
return code, state.Error()
|
return code, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetStorageAt returns the storage from the state at the given address, key and
|
// GetStorageAt returns the storage from the state at the given address, key and
|
||||||
|
@ -620,7 +620,7 @@ func (s *PublicBlockChainAPI) GetStorageAt(ctx context.Context, address common.A
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
res := state.GetState(address, common.HexToHash(key))
|
res := state.GetState(address, common.HexToHash(key))
|
||||||
return res[:], state.Error()
|
return res[:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CallArgs represents the arguments for a call.
|
// CallArgs represents the arguments for a call.
|
||||||
|
@ -1030,7 +1030,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionCount(ctx context.Context, addr
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
nonce := state.GetNonce(address)
|
nonce := state.GetNonce(address)
|
||||||
return (*hexutil.Uint64)(&nonce), state.Error()
|
return (*hexutil.Uint64)(&nonce), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransactionByHash returns the transaction for the given hash
|
// GetTransactionByHash returns the transaction for the given hash
|
||||||
|
@ -1273,7 +1273,7 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
|
||||||
var chainID *big.Int
|
var chainID *big.Int
|
||||||
isQuorum := false
|
isQuorum := false
|
||||||
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
if config := s.b.ChainConfig(); config.IsEIP155(s.b.CurrentBlock().Number()) {
|
||||||
chainID = config.ChainId
|
chainID = config.ChainID
|
||||||
isQuorum = true
|
isQuorum = true
|
||||||
}
|
}
|
||||||
signed, err := wallet.SignTx(account, tx, chainID, isQuorum)
|
signed, err := wallet.SignTx(account, tx, chainID, isQuorum)
|
||||||
|
|
|
@ -24,7 +24,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/accounts"
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"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/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
@ -65,7 +64,6 @@ type Backend interface {
|
||||||
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
|
GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error)
|
||||||
Stats() (pending int, queued int)
|
Stats() (pending int, queued int)
|
||||||
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||||
SubscribeTxPreEvent(chan<- core.TxPreEvent) event.Subscription
|
|
||||||
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
|
|
|
@ -137,10 +137,6 @@ func (b *LesApiBackend) TxPoolContent() (map[common.Address]types.Transactions,
|
||||||
return b.eth.txPool.Content()
|
return b.eth.txPool.Content()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) SubscribeTxPreEvent(ch chan<- core.TxPreEvent) event.Subscription {
|
|
||||||
return b.eth.txPool.SubscribeTxPreEvent(ch)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b *LesApiBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
|
func (b *LesApiBackend) SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription {
|
||||||
return b.eth.txPool.SubscribeNewTxsEvent(ch)
|
return b.eth.txPool.SubscribeNewTxsEvent(ch)
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,7 +79,7 @@ type BlockChain interface {
|
||||||
GetHeaderByHash(hash common.Hash) *types.Header
|
GetHeaderByHash(hash common.Hash) *types.Header
|
||||||
CurrentHeader() *types.Header
|
CurrentHeader() *types.Header
|
||||||
GetTd(hash common.Hash, number uint64) *big.Int
|
GetTd(hash common.Hash, number uint64) *big.Int
|
||||||
State() (*state.StateDB, error)
|
State() (*state.StateDB, *state.StateDB, error)
|
||||||
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
|
||||||
|
@ -605,7 +605,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
// Retrieve the requested state entry, stopping if enough was found
|
// Retrieve the requested state entry, stopping if enough was found
|
||||||
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
||||||
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
||||||
statedb, err := pm.blockchain.State()
|
statedb, _, err := pm.blockchain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -736,7 +736,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
// Retrieve the requested state entry, stopping if enough was found
|
// Retrieve the requested state entry, stopping if enough was found
|
||||||
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
||||||
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
||||||
statedb, err := pm.blockchain.State()
|
statedb, _, err := pm.blockchain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -796,7 +796,7 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
|
|
||||||
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
if number := rawdb.ReadHeaderNumber(pm.chainDb, req.BHash); number != nil {
|
||||||
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
if header := rawdb.ReadHeader(pm.chainDb, req.BHash, *number); header != nil {
|
||||||
statedb, _ = pm.blockchain.State()
|
statedb, _, _ = pm.blockchain.State()
|
||||||
root = header.Root
|
root = header.Root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,8 +209,8 @@ func (bc *LightChain) Genesis() *types.Block {
|
||||||
}
|
}
|
||||||
|
|
||||||
// State returns a new mutable state based on the current HEAD block.
|
// State returns a new mutable state based on the current HEAD block.
|
||||||
func (bc *LightChain) State() (*state.StateDB, error) {
|
func (bc *LightChain) State() (*state.StateDB, *state.StateDB, error) {
|
||||||
return nil, errors.New("not implemented, needs client/server interface split")
|
return nil, nil, errors.New("not implemented, needs client/server interface split")
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBody retrieves a block body (transactions and uncles) from the database
|
// GetBody retrieves a block body (transactions and uncles) from the database
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package p2p
|
package p2p
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
|
|
@ -857,7 +857,6 @@ func (srv *Server) setupConn(c *conn, flags connFlag, dialDest *discover.Node) e
|
||||||
|
|
||||||
//END - QUORUM Permissioning
|
//END - QUORUM Permissioning
|
||||||
|
|
||||||
clog := srv.log.New("id", c.id, "addr", c.fd.RemoteAddr(), "conn", c.flags)
|
|
||||||
// For dialed connections, check that the remote public key matches.
|
// For dialed connections, check that the remote public key matches.
|
||||||
if dialDest != nil && c.id != dialDest.ID {
|
if dialDest != nil && c.id != dialDest.ID {
|
||||||
clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
|
clog.Trace("Dialed identity mismatch", "want", c, dialDest.ID)
|
||||||
|
|
|
@ -81,7 +81,7 @@ var (
|
||||||
|
|
||||||
// OttomanChainConfig contains the chain parameters to run a node on the Ottoman test network.
|
// OttomanChainConfig contains the chain parameters to run a node on the Ottoman test network.
|
||||||
OttomanChainConfig = &ChainConfig{
|
OttomanChainConfig = &ChainConfig{
|
||||||
ChainId: big.NewInt(5),
|
ChainID: big.NewInt(5),
|
||||||
HomesteadBlock: big.NewInt(1),
|
HomesteadBlock: big.NewInt(1),
|
||||||
DAOForkBlock: nil,
|
DAOForkBlock: nil,
|
||||||
DAOForkSupport: true,
|
DAOForkSupport: true,
|
||||||
|
|
|
@ -77,6 +77,7 @@ const (
|
||||||
Bn256ScalarMulGas uint64 = 40000 // Gas needed for an elliptic curve scalar multiplication
|
Bn256ScalarMulGas uint64 = 40000 // Gas needed for an elliptic curve scalar multiplication
|
||||||
Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check
|
Bn256PairingBaseGas uint64 = 100000 // Base price for an elliptic curve pairing check
|
||||||
Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check
|
Bn256PairingPerPointGas uint64 = 80000 // Per-point price for an elliptic curve pairing check
|
||||||
|
QuorumMaximumExtraDataSize uint64 = 65 // Maximum size extra data may be after Genesis.
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -85,3 +86,11 @@ var (
|
||||||
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
|
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
|
||||||
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
|
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func GetMaximumExtraDataSize(isQuorum bool) uint64 {
|
||||||
|
if isQuorum {
|
||||||
|
return QuorumMaximumExtraDataSize
|
||||||
|
} else {
|
||||||
|
return MaximumExtraDataSize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ type minter struct {
|
||||||
invalidRaftOrderingChan chan InvalidRaftOrdering
|
invalidRaftOrderingChan chan InvalidRaftOrdering
|
||||||
chainHeadChan chan core.ChainHeadEvent
|
chainHeadChan chan core.ChainHeadEvent
|
||||||
chainHeadSub event.Subscription
|
chainHeadSub event.Subscription
|
||||||
txPreChan chan core.TxPreEvent
|
txPreChan chan core.NewTxsEvent
|
||||||
txPreSub event.Subscription
|
txPreSub event.Subscription
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,11 +79,11 @@ func newMinter(config *params.ChainConfig, eth *RaftService, blockTime time.Dura
|
||||||
|
|
||||||
invalidRaftOrderingChan: make(chan InvalidRaftOrdering, 1),
|
invalidRaftOrderingChan: make(chan InvalidRaftOrdering, 1),
|
||||||
chainHeadChan: make(chan core.ChainHeadEvent, 1),
|
chainHeadChan: make(chan core.ChainHeadEvent, 1),
|
||||||
txPreChan: make(chan core.TxPreEvent, 4096),
|
txPreChan: make(chan core.NewTxsEvent, 4096),
|
||||||
}
|
}
|
||||||
|
|
||||||
minter.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(minter.chainHeadChan)
|
minter.chainHeadSub = eth.BlockChain().SubscribeChainHeadEvent(minter.chainHeadChan)
|
||||||
minter.txPreSub = eth.TxPool().SubscribeTxPreEvent(minter.txPreChan)
|
minter.txPreSub = eth.TxPool().SubscribeNewTxsEvent(minter.txPreChan)
|
||||||
|
|
||||||
minter.speculativeChain.clear(minter.chain.CurrentBlock())
|
minter.speculativeChain.clear(minter.chain.CurrentBlock())
|
||||||
|
|
||||||
|
|
|
@ -125,7 +125,7 @@ func (t *BlockTest) Run() error {
|
||||||
if common.Hash(t.json.BestBlock) != cmlast {
|
if common.Hash(t.json.BestBlock) != cmlast {
|
||||||
return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
|
return fmt.Errorf("last block hash validation mismatch: want: %x, have: %x", t.json.BestBlock, cmlast)
|
||||||
}
|
}
|
||||||
newDB, err := chain.State()
|
newDB, _, err := chain.State()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue