mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge branch 'develop' of https://github.com/ethereum/go-ethereum into develop
This commit is contained in:
commit
00295c2f64
1007 changed files with 153218 additions and 67014 deletions
23
.travis.yml
23
.travis.yml
|
|
@ -53,15 +53,36 @@ matrix:
|
||||||
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
- CC=aarch64-linux-gnu-gcc go run build/ci.go install -arch arm64
|
||||||
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -arch arm64 -type tar -signer LINUX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
# This builder does the OSX Azure uploads
|
# This builder does the OSX Azure, Android Maven and Azure and iOS CocoaPods and Azure uploads
|
||||||
- os: osx
|
- os: osx
|
||||||
go: 1.7
|
go: 1.7
|
||||||
env:
|
env:
|
||||||
- azure-osx
|
- azure-osx
|
||||||
|
- mobile
|
||||||
|
cache:
|
||||||
|
directories:
|
||||||
|
- $HOME/.android.platforms
|
||||||
|
- $HOME/.cocoapods
|
||||||
script:
|
script:
|
||||||
- go run build/ci.go install
|
- go run build/ci.go install
|
||||||
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
- go run build/ci.go archive -type tar -signer OSX_SIGNING_KEY -upload gethstore/builds
|
||||||
|
|
||||||
|
# Build the iOS framework and upload it to CocoaPods and Azure
|
||||||
|
- gem install cocoapods --pre
|
||||||
|
- travis_wait 30 go run build/ci.go xcode -signer IOS_SIGNING_KEY -deploy trunk -upload gethstore/builds
|
||||||
|
|
||||||
|
# Build the Android archive and upload it to Maven Central and Azure
|
||||||
|
- brew update
|
||||||
|
- brew install android-sdk maven
|
||||||
|
- export ANDROID_HOME=/usr/local/opt/android-sdk
|
||||||
|
|
||||||
|
- mkdir -p $ANDROID_HOME/platforms
|
||||||
|
- mv -f $HOME/.android.platforms $ANDROID_HOME/platforms
|
||||||
|
- echo "y" | android update sdk --no-ui --filter platform
|
||||||
|
|
||||||
|
- go run build/ci.go aar -signer ANDROID_SIGNING_KEY -deploy https://oss.sonatype.org -upload gethstore/builds
|
||||||
|
- mv -f $ANDROID_HOME/platforms $HOME/.android.platforms
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go get golang.org/x/tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
script:
|
script:
|
||||||
|
|
|
||||||
|
|
@ -48,15 +48,15 @@ func NewKeyedTransactor(key *ecdsa.PrivateKey) *TransactOpts {
|
||||||
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
keyAddr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
return &TransactOpts{
|
return &TransactOpts{
|
||||||
From: keyAddr,
|
From: keyAddr,
|
||||||
Signer: func(address common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
Signer: func(signer types.Signer, address common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
if address != keyAddr {
|
if address != keyAddr {
|
||||||
return nil, errors.New("not authorized to sign this account")
|
return nil, errors.New("not authorized to sign this account")
|
||||||
}
|
}
|
||||||
signature, err := crypto.SignEthereum(tx.SigHash().Bytes(), key)
|
signature, err := crypto.SignEthereum(signer.Hash(tx).Bytes(), key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return tx.WithSignature(signature)
|
return tx.WithSignature(signer, signature)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,11 +31,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
// Default chain configuration which sets homestead phase at block 0 (i.e. no frontier)
|
||||||
var chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
var chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), EIP150Block: new(big.Int), EIP158Block: new(big.Int)}
|
||||||
|
|
||||||
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
// This nil assignment ensures compile time that SimulatedBackend implements bind.ContractBackend.
|
||||||
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
var _ bind.ContractBackend = (*SimulatedBackend)(nil)
|
||||||
|
|
@ -51,6 +52,8 @@ type SimulatedBackend struct {
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
pendingBlock *types.Block // Currently pending block that will be imported on request
|
pendingBlock *types.Block // Currently pending block that will be imported on request
|
||||||
pendingState *state.StateDB // Currently pending state that will be the active on on request
|
pendingState *state.StateDB // Currently pending state that will be the active on on request
|
||||||
|
|
||||||
|
config *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
// NewSimulatedBackend creates a new binding backend using a simulated blockchain
|
||||||
|
|
@ -85,7 +88,7 @@ func (b *SimulatedBackend) Rollback() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *SimulatedBackend) rollback() {
|
func (b *SimulatedBackend) rollback() {
|
||||||
blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
|
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(int, *core.BlockGen) {})
|
||||||
b.pendingBlock = blocks[0]
|
b.pendingBlock = blocks[0]
|
||||||
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
b.pendingState, _ = state.New(b.pendingBlock.Root(), b.database)
|
||||||
}
|
}
|
||||||
|
|
@ -234,7 +237,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
b.mu.Lock()
|
b.mu.Lock()
|
||||||
defer b.mu.Unlock()
|
defer b.mu.Unlock()
|
||||||
|
|
||||||
sender, err := tx.From()
|
sender, err := types.Sender(types.HomesteadSigner{}, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Errorf("invalid transaction: %v", err))
|
panic(fmt.Errorf("invalid transaction: %v", err))
|
||||||
}
|
}
|
||||||
|
|
@ -243,7 +246,7 @@ func (b *SimulatedBackend) SendTransaction(ctx context.Context, tx *types.Transa
|
||||||
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
panic(fmt.Errorf("invalid transaction nonce: got %d, want %d", tx.Nonce(), nonce))
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks, _ := core.GenerateChain(nil, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(chainConfig, b.blockchain.CurrentBlock(), b.database, 1, func(number int, block *core.BlockGen) {
|
||||||
for _, tx := range b.pendingBlock.Transactions() {
|
for _, tx := range b.pendingBlock.Transactions() {
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
}
|
}
|
||||||
|
|
@ -259,12 +262,11 @@ type callmsg struct {
|
||||||
ethereum.CallMsg
|
ethereum.CallMsg
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m callmsg) From() (common.Address, error) { return m.CallMsg.From, nil }
|
func (m callmsg) From() common.Address { return m.CallMsg.From }
|
||||||
func (m callmsg) FromFrontier() (common.Address, error) { return m.CallMsg.From, nil }
|
func (m callmsg) Nonce() uint64 { return 0 }
|
||||||
func (m callmsg) Nonce() uint64 { return 0 }
|
func (m callmsg) CheckNonce() bool { return false }
|
||||||
func (m callmsg) CheckNonce() bool { return false }
|
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
||||||
func (m callmsg) To() *common.Address { return m.CallMsg.To }
|
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
||||||
func (m callmsg) GasPrice() *big.Int { return m.CallMsg.GasPrice }
|
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
|
||||||
func (m callmsg) Gas() *big.Int { return m.CallMsg.Gas }
|
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
||||||
func (m callmsg) Value() *big.Int { return m.CallMsg.Value }
|
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
||||||
func (m callmsg) Data() []byte { return m.CallMsg.Data }
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
|
|
||||||
// SignerFn is a signer function callback when a contract requires a method to
|
// SignerFn is a signer function callback when a contract requires a method to
|
||||||
// sign the transaction before submission.
|
// sign the transaction before submission.
|
||||||
type SignerFn func(common.Address, *types.Transaction) (*types.Transaction, error)
|
type SignerFn func(types.Signer, common.Address, *types.Transaction) (*types.Transaction, error)
|
||||||
|
|
||||||
// CallOpts is the collection of options to fine tune a contract call request.
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
type CallOpts struct {
|
type CallOpts struct {
|
||||||
|
|
@ -214,7 +214,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
||||||
if opts.Signer == nil {
|
if opts.Signer == nil {
|
||||||
return nil, errors.New("no signer to authorize the transaction with")
|
return nil, errors.New("no signer to authorize the transaction with")
|
||||||
}
|
}
|
||||||
signedTx, err := opts.Signer(opts.From, rawTx)
|
signedTx, err := opts.Signer(types.HomesteadSigner{}, opts.From, rawTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,20 @@ import (
|
||||||
"golang.org/x/tools/imports"
|
"golang.org/x/tools/imports"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Lang is a target programming language selector to generate bindings for.
|
||||||
|
type Lang int
|
||||||
|
|
||||||
|
const (
|
||||||
|
LangGo Lang = iota
|
||||||
|
LangJava
|
||||||
|
LangObjC
|
||||||
|
)
|
||||||
|
|
||||||
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
// Bind generates a Go wrapper around a contract ABI. This wrapper isn't meant
|
||||||
// to be used as is in client code, but rather as an intermediate struct which
|
// to be used as is in client code, but rather as an intermediate struct which
|
||||||
// enforces compile time type safety and naming convention opposed to having to
|
// enforces compile time type safety and naming convention opposed to having to
|
||||||
// manually maintain hard coded strings that break on runtime.
|
// manually maintain hard coded strings that break on runtime.
|
||||||
func Bind(types []string, abis []string, bytecodes []string, pkg string) (string, error) {
|
func Bind(types []string, abis []string, bytecodes []string, pkg string, lang Lang) (string, error) {
|
||||||
// Process each individual contract requested binding
|
// Process each individual contract requested binding
|
||||||
contracts := make(map[string]*tmplContract)
|
contracts := make(map[string]*tmplContract)
|
||||||
|
|
||||||
|
|
@ -62,7 +71,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
||||||
for _, original := range evmABI.Methods {
|
for _, original := range evmABI.Methods {
|
||||||
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
// Normalize the method for capital cases and non-anonymous inputs/outputs
|
||||||
normalized := original
|
normalized := original
|
||||||
normalized.Name = capitalise(original.Name)
|
normalized.Name = methodNormalizer[lang](original.Name)
|
||||||
|
|
||||||
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
normalized.Inputs = make([]abi.Argument, len(original.Inputs))
|
||||||
copy(normalized.Inputs, original.Inputs)
|
copy(normalized.Inputs, original.Inputs)
|
||||||
|
|
@ -78,7 +87,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
||||||
normalized.Outputs[j].Name = capitalise(output.Name)
|
normalized.Outputs[j].Name = capitalise(output.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Append the methos to the call or transact lists
|
// Append the methods to the call or transact lists
|
||||||
if original.Const {
|
if original.Const {
|
||||||
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
|
calls[original.Name] = &tmplMethod{Original: original, Normalized: normalized, Structured: structured(original)}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -87,7 +96,7 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
||||||
}
|
}
|
||||||
contracts[types[i]] = &tmplContract{
|
contracts[types[i]] = &tmplContract{
|
||||||
Type: capitalise(types[i]),
|
Type: capitalise(types[i]),
|
||||||
InputABI: strippedABI,
|
InputABI: strings.Replace(strippedABI, "\"", "\\\"", -1),
|
||||||
InputBin: strings.TrimSpace(bytecodes[i]),
|
InputBin: strings.TrimSpace(bytecodes[i]),
|
||||||
Constructor: evmABI.Constructor,
|
Constructor: evmABI.Constructor,
|
||||||
Calls: calls,
|
Calls: calls,
|
||||||
|
|
@ -102,24 +111,38 @@ func Bind(types []string, abis []string, bytecodes []string, pkg string) (string
|
||||||
buffer := new(bytes.Buffer)
|
buffer := new(bytes.Buffer)
|
||||||
|
|
||||||
funcs := map[string]interface{}{
|
funcs := map[string]interface{}{
|
||||||
"bindtype": bindType,
|
"bindtype": bindType[lang],
|
||||||
|
"namedtype": namedType[lang],
|
||||||
|
"capitalise": capitalise,
|
||||||
|
"decapitalise": decapitalise,
|
||||||
}
|
}
|
||||||
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource))
|
tmpl := template.Must(template.New("").Funcs(funcs).Parse(tmplSource[lang]))
|
||||||
if err := tmpl.Execute(buffer, data); err != nil {
|
if err := tmpl.Execute(buffer, data); err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Pass the code through goimports to clean it up and double check
|
// For Go bindings pass the code through goimports to clean it up and double check
|
||||||
code, err := imports.Process("", buffer.Bytes(), nil)
|
if lang == LangGo {
|
||||||
if err != nil {
|
code, err := imports.Process("", buffer.Bytes(), nil)
|
||||||
return "", fmt.Errorf("%v\n%s", err, buffer)
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("%v\n%s", err, buffer)
|
||||||
|
}
|
||||||
|
return string(code), nil
|
||||||
}
|
}
|
||||||
return string(code), nil
|
// For all others just return as is for now
|
||||||
|
return string(buffer.Bytes()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// bindType converts a Solidity type to a Go one. Since there is no clear mapping
|
// bindType is a set of type binders that convert Solidity types to some supported
|
||||||
|
// programming language.
|
||||||
|
var bindType = map[Lang]func(kind abi.Type) string{
|
||||||
|
LangGo: bindTypeGo,
|
||||||
|
LangJava: bindTypeJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// bindTypeGo converts a Solidity type to a Go one. Since there is no clear mapping
|
||||||
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
// from all Solidity types to Go ones (e.g. uint17), those that cannot be exactly
|
||||||
// mapped will use an upscaled type (e.g. *big.Int).
|
// mapped will use an upscaled type (e.g. *big.Int).
|
||||||
func bindType(kind abi.Type) string {
|
func bindTypeGo(kind abi.Type) string {
|
||||||
stringKind := kind.String()
|
stringKind := kind.String()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|
@ -160,11 +183,137 @@ func bindType(kind abi.Type) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// bindTypeJava converts a Solidity type to a Java one. Since there is no clear mapping
|
||||||
|
// from all Solidity types to Java ones (e.g. uint17), those that cannot be exactly
|
||||||
|
// mapped will use an upscaled type (e.g. BigDecimal).
|
||||||
|
func bindTypeJava(kind abi.Type) string {
|
||||||
|
stringKind := kind.String()
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(stringKind, "address"):
|
||||||
|
parts := regexp.MustCompile("address(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("Address")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("Addresses")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "bytes"):
|
||||||
|
parts := regexp.MustCompile("bytes([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 3 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[2] != "" {
|
||||||
|
return "byte[][]"
|
||||||
|
}
|
||||||
|
return "byte[]"
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "int") || strings.HasPrefix(stringKind, "uint"):
|
||||||
|
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
switch parts[2] {
|
||||||
|
case "8", "16", "32", "64":
|
||||||
|
if parts[1] == "" {
|
||||||
|
if parts[3] == "" {
|
||||||
|
return fmt.Sprintf("int%s", parts[2])
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("int%s[]", parts[2])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if parts[3] == "" {
|
||||||
|
return fmt.Sprintf("BigInt")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("BigInts")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "bool"):
|
||||||
|
parts := regexp.MustCompile("bool(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("bool")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("bool[]")
|
||||||
|
|
||||||
|
case strings.HasPrefix(stringKind, "string"):
|
||||||
|
parts := regexp.MustCompile("string(\\[[0-9]*\\])?").FindStringSubmatch(stringKind)
|
||||||
|
if len(parts) != 2 {
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
if parts[1] == "" {
|
||||||
|
return fmt.Sprintf("String")
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("String[]")
|
||||||
|
|
||||||
|
default:
|
||||||
|
return stringKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// namedType is a set of functions that transform language specific types to
|
||||||
|
// named versions that my be used inside method names.
|
||||||
|
var namedType = map[Lang]func(string, abi.Type) string{
|
||||||
|
LangGo: func(string, abi.Type) string { panic("this shouldn't be needed") },
|
||||||
|
LangJava: namedTypeJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// namedTypeJava converts some primitive data types to named variants that can
|
||||||
|
// be used as parts of method names.
|
||||||
|
func namedTypeJava(javaKind string, solKind abi.Type) string {
|
||||||
|
switch javaKind {
|
||||||
|
case "byte[]":
|
||||||
|
return "Binary"
|
||||||
|
case "byte[][]":
|
||||||
|
return "Binaries"
|
||||||
|
case "string":
|
||||||
|
return "String"
|
||||||
|
case "string[]":
|
||||||
|
return "Strings"
|
||||||
|
case "bool":
|
||||||
|
return "Bool"
|
||||||
|
case "bool[]":
|
||||||
|
return "Bools"
|
||||||
|
case "BigInt":
|
||||||
|
parts := regexp.MustCompile("(u)?int([0-9]*)(\\[[0-9]*\\])?").FindStringSubmatch(solKind.String())
|
||||||
|
if len(parts) != 4 {
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
switch parts[2] {
|
||||||
|
case "8", "16", "32", "64":
|
||||||
|
if parts[3] == "" {
|
||||||
|
return capitalise(fmt.Sprintf("%sint%s", parts[1], parts[2]))
|
||||||
|
}
|
||||||
|
return capitalise(fmt.Sprintf("%sint%ss", parts[1], parts[2]))
|
||||||
|
|
||||||
|
default:
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return javaKind
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// methodNormalizer is a name transformer that modifies Solidity method names to
|
||||||
|
// conform to target language naming concentions.
|
||||||
|
var methodNormalizer = map[Lang]func(string) string{
|
||||||
|
LangGo: capitalise,
|
||||||
|
LangJava: decapitalise,
|
||||||
|
}
|
||||||
|
|
||||||
// capitalise makes the first character of a string upper case.
|
// capitalise makes the first character of a string upper case.
|
||||||
func capitalise(input string) string {
|
func capitalise(input string) string {
|
||||||
return strings.ToUpper(input[:1]) + input[1:]
|
return strings.ToUpper(input[:1]) + input[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// decapitalise makes the first character of a string lower case.
|
||||||
|
func decapitalise(input string) string {
|
||||||
|
return strings.ToLower(input[:1]) + input[1:]
|
||||||
|
}
|
||||||
|
|
||||||
// structured checks whether a method has enough information to return a proper
|
// structured checks whether a method has enough information to return a proper
|
||||||
// Go struct ot if flat returns are needed.
|
// Go struct ot if flat returns are needed.
|
||||||
func structured(method abi.Method) bool {
|
func structured(method abi.Method) bool {
|
||||||
|
|
|
||||||
|
|
@ -398,7 +398,7 @@ func TestBindings(t *testing.T) {
|
||||||
// Generate the test suite for all the contracts
|
// Generate the test suite for all the contracts
|
||||||
for i, tt := range bindTests {
|
for i, tt := range bindTests {
|
||||||
// Generate the binding and create a Go source file in the workspace
|
// Generate the binding and create a Go source file in the workspace
|
||||||
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest")
|
bind, err := Bind([]string{tt.name}, []string{tt.abi}, []string{tt.bytecode}, "bindtest", LangGo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
t.Fatalf("test %d: failed to generate binding: %v", i, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,16 @@ type tmplMethod struct {
|
||||||
Structured bool // Whether the returns should be accumulated into a contract
|
Structured bool // Whether the returns should be accumulated into a contract
|
||||||
}
|
}
|
||||||
|
|
||||||
// tmplSource is the Go source template use to generate the contract binding
|
// tmplSource is language to template mapping containing all the supported
|
||||||
|
// programming languages the package can generate to.
|
||||||
|
var tmplSource = map[Lang]string{
|
||||||
|
LangGo: tmplSourceGo,
|
||||||
|
LangJava: tmplSourceJava,
|
||||||
|
}
|
||||||
|
|
||||||
|
// tmplSourceGo is the Go source template use to generate the contract binding
|
||||||
// based on.
|
// based on.
|
||||||
const tmplSource = `
|
const tmplSourceGo = `
|
||||||
// This file is an automatically generated Go binding. Do not modify as any
|
// This file is an automatically generated Go binding. Do not modify as any
|
||||||
// change will likely be lost upon the next re-generation!
|
// change will likely be lost upon the next re-generation!
|
||||||
|
|
||||||
|
|
@ -52,7 +59,7 @@ package {{.Package}}
|
||||||
|
|
||||||
{{range $contract := .Contracts}}
|
{{range $contract := .Contracts}}
|
||||||
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
// {{.Type}}ABI is the input ABI used to generate the binding from.
|
||||||
const {{.Type}}ABI = ` + "`" + `{{.InputABI}}` + "`" + `
|
const {{.Type}}ABI = "{{.InputABI}}"
|
||||||
|
|
||||||
{{if .InputBin}}
|
{{if .InputBin}}
|
||||||
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
// {{.Type}}Bin is the compiled bytecode used for deploying new contracts.
|
||||||
|
|
@ -258,3 +265,105 @@ package {{.Package}}
|
||||||
{{end}}
|
{{end}}
|
||||||
{{end}}
|
{{end}}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// tmplSourceJava is the Java source template use to generate the contract binding
|
||||||
|
// based on.
|
||||||
|
const tmplSourceJava = `
|
||||||
|
// This file is an automatically generated Java binding. Do not modify as any
|
||||||
|
// change will likely be lost upon the next re-generation!
|
||||||
|
|
||||||
|
package {{.Package}};
|
||||||
|
|
||||||
|
import org.ethereum.geth.*;
|
||||||
|
import org.ethereum.geth.internal.*;
|
||||||
|
|
||||||
|
{{range $contract := .Contracts}}
|
||||||
|
public class {{.Type}} {
|
||||||
|
// ABI is the input ABI used to generate the binding from.
|
||||||
|
public final static String ABI = "{{.InputABI}}";
|
||||||
|
|
||||||
|
{{if .InputBin}}
|
||||||
|
// BYTECODE is the compiled bytecode used for deploying new contracts.
|
||||||
|
public final static byte[] BYTECODE = "{{.InputBin}}".getBytes();
|
||||||
|
|
||||||
|
// deploy deploys a new Ethereum contract, binding an instance of {{.Type}} to it.
|
||||||
|
public static {{.Type}} deploy(TransactOpts auth, EthereumClient client{{range .Constructor.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Constructor.Inputs)}});
|
||||||
|
{{range $index, $element := .Constructor.Inputs}}
|
||||||
|
args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
return new {{.Type}}(Geth.deployContract(auth, ABI, BYTECODE, client, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal constructor used by contract deployment.
|
||||||
|
private {{.Type}}(BoundContract deployment) {
|
||||||
|
this.Address = deployment.getAddress();
|
||||||
|
this.Deployer = deployment.getDeployer();
|
||||||
|
this.Contract = deployment;
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// Ethereum address where this contract is located at.
|
||||||
|
public final Address Address;
|
||||||
|
|
||||||
|
// Ethereum transaction in which this contract was deployed (if known!).
|
||||||
|
public final Transaction Deployer;
|
||||||
|
|
||||||
|
// Contract instance bound to a blockchain address.
|
||||||
|
private final BoundContract Contract;
|
||||||
|
|
||||||
|
// Creates a new instance of {{.Type}}, bound to a specific deployed contract.
|
||||||
|
public {{.Type}}(Address address, EthereumClient client) throws Exception {
|
||||||
|
this(Geth.bindContract(address, ABI, client));
|
||||||
|
}
|
||||||
|
|
||||||
|
{{range .Calls}}
|
||||||
|
{{if gt (len .Normalized.Outputs) 1}}
|
||||||
|
// {{capitalise .Normalized.Name}}Results is the output of a call to {{.Normalized.Name}}.
|
||||||
|
public class {{capitalise .Normalized.Name}}Results {
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}public {{bindtype .Type}} {{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}};
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
// {{.Normalized.Name}} is a free data retrieval call binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||||
|
//
|
||||||
|
// Solidity: {{.Original.String}}
|
||||||
|
public {{if gt (len .Normalized.Outputs) 1}}{{capitalise .Normalized.Name}}Results{{else}}{{range .Normalized.Outputs}}{{bindtype .Type}}{{end}}{{end}} {{.Normalized.Name}}(CallOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
Interfaces results = Geth.newInterfaces({{(len .Normalized.Outputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}Interface result{{$index}} = Geth.newInterface(); result{{$index}}.setDefault{{namedtype (bindtype .Type) .Type}}(); results.set({{$index}}, result{{$index}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
if (opts == null) {
|
||||||
|
opts = Geth.newCallOpts();
|
||||||
|
}
|
||||||
|
this.Contract.call(opts, results, "{{.Original.Name}}", args);
|
||||||
|
{{if gt (len .Normalized.Outputs) 1}}
|
||||||
|
{{capitalise .Normalized.Name}}Results result = new {{capitalise .Normalized.Name}}Results();
|
||||||
|
{{range $index, $item := .Normalized.Outputs}}result.{{if ne .Name ""}}{{.Name}}{{else}}Return{{$index}}{{end}} = results.get({{$index}}).get{{namedtype (bindtype .Type) .Type}}();
|
||||||
|
{{end}}
|
||||||
|
return result;
|
||||||
|
{{else}}{{range .Normalized.Outputs}}return results.get(0).get{{namedtype (bindtype .Type) .Type}}();{{end}}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
{{range .Transacts}}
|
||||||
|
// {{.Normalized.Name}} is a paid mutator transaction binding the contract method 0x{{printf "%x" .Original.Id}}.
|
||||||
|
//
|
||||||
|
// Solidity: {{.Original.String}}
|
||||||
|
public Transaction {{.Normalized.Name}}(TransactOpts opts{{range .Normalized.Inputs}}, {{bindtype .Type}} {{.Name}}{{end}}) throws Exception {
|
||||||
|
Interfaces args = Geth.newInterfaces({{(len .Normalized.Inputs)}});
|
||||||
|
{{range $index, $item := .Normalized.Inputs}}args.set({{$index}}, Geth.newInterface()); args.get({{$index}}).set{{namedtype (bindtype .Type) .Type}}({{.Name}});
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
return this.Contract.transact(opts, "{{.Original.Name}}" , args);
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
}
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func TestWaitDeployed(t *testing.T) {
|
||||||
|
|
||||||
// Create the transaction.
|
// Create the transaction.
|
||||||
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
|
tx := types.NewContractCreation(0, big.NewInt(0), test.gas, big.NewInt(1), common.FromHex(test.code))
|
||||||
tx, _ = tx.SignECDSA(testKey)
|
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, testKey)
|
||||||
|
|
||||||
// Wait for it to get mined in the background.
|
// Wait for it to get mined in the background.
|
||||||
var (
|
var (
|
||||||
|
|
|
||||||
|
|
@ -46,12 +46,20 @@ import (
|
||||||
const (
|
const (
|
||||||
keyHeaderKDF = "scrypt"
|
keyHeaderKDF = "scrypt"
|
||||||
|
|
||||||
// n,r,p = 2^18, 8, 1 uses 256MB memory and approx 1s CPU time on a modern CPU.
|
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
StandardScryptN = 1 << 18
|
StandardScryptN = 1 << 18
|
||||||
|
|
||||||
|
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
StandardScryptP = 1
|
StandardScryptP = 1
|
||||||
|
|
||||||
// n,r,p = 2^12, 8, 6 uses 4MB memory and approx 100ms CPU time on a modern CPU.
|
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
LightScryptN = 1 << 12
|
LightScryptN = 1 << 12
|
||||||
|
|
||||||
|
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
LightScryptP = 6
|
LightScryptP = 6
|
||||||
|
|
||||||
scryptR = 8
|
scryptR = 8
|
||||||
|
|
|
||||||
224
build/ci.go
224
build/ci.go
|
|
@ -29,6 +29,8 @@ Available commands are:
|
||||||
importkeys -- imports signing keys from env
|
importkeys -- imports signing keys from env
|
||||||
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
debsrc [ -signer key-id ] [ -upload dest ] -- creates a debian source package
|
||||||
nsis -- creates a Windows NSIS installer
|
nsis -- creates a Windows NSIS installer
|
||||||
|
aar [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an Android archive
|
||||||
|
xcode [ -sign key-id ] [-deploy repo] [ -upload dest ] -- creates an iOS XCode framework
|
||||||
xgo [ options ] -- cross builds according to options
|
xgo [ options ] -- cross builds according to options
|
||||||
|
|
||||||
For all commands, -n prevents execution of external programs (dry run mode).
|
For all commands, -n prevents execution of external programs (dry run mode).
|
||||||
|
|
@ -37,6 +39,7 @@ For all commands, -n prevents execution of external programs (dry run mode).
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"flag"
|
"flag"
|
||||||
|
|
@ -48,6 +51,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -125,6 +129,10 @@ func main() {
|
||||||
doDebianSource(os.Args[2:])
|
doDebianSource(os.Args[2:])
|
||||||
case "nsis":
|
case "nsis":
|
||||||
doWindowsInstaller(os.Args[2:])
|
doWindowsInstaller(os.Args[2:])
|
||||||
|
case "aar":
|
||||||
|
doAndroidArchive(os.Args[2:])
|
||||||
|
case "xcode":
|
||||||
|
doXCodeFramework(os.Args[2:])
|
||||||
case "xgo":
|
case "xgo":
|
||||||
doXgo(os.Args[2:])
|
doXgo(os.Args[2:])
|
||||||
default:
|
default:
|
||||||
|
|
@ -331,14 +339,24 @@ func archiveBasename(arch string, env build.Environment) string {
|
||||||
if arch == "arm" {
|
if arch == "arm" {
|
||||||
platform += os.Getenv("GOARM")
|
platform += os.Getenv("GOARM")
|
||||||
}
|
}
|
||||||
archive := platform + "-" + build.VERSION()
|
if arch == "android" {
|
||||||
|
platform = "android-all"
|
||||||
|
}
|
||||||
|
if arch == "ios" {
|
||||||
|
platform = "ios-all"
|
||||||
|
}
|
||||||
|
return platform + "-" + archiveVersion(env)
|
||||||
|
}
|
||||||
|
|
||||||
|
func archiveVersion(env build.Environment) string {
|
||||||
|
version := build.VERSION()
|
||||||
if isUnstableBuild(env) {
|
if isUnstableBuild(env) {
|
||||||
archive += "-unstable"
|
version += "-unstable"
|
||||||
}
|
}
|
||||||
if env.Commit != "" {
|
if env.Commit != "" {
|
||||||
archive += "-" + env.Commit[:8]
|
version += "-" + env.Commit[:8]
|
||||||
}
|
}
|
||||||
return archive
|
return version
|
||||||
}
|
}
|
||||||
|
|
||||||
func archiveUpload(archive string, blobstore string, signer string) error {
|
func archiveUpload(archive string, blobstore string, signer string) error {
|
||||||
|
|
@ -632,6 +650,204 @@ func doWindowsInstaller(cmdline []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Android archives
|
||||||
|
|
||||||
|
func doAndroidArchive(cmdline []string) {
|
||||||
|
var (
|
||||||
|
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. ANDROID_SIGNING_KEY)`)
|
||||||
|
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "https://oss.sonatype.org")`)
|
||||||
|
upload = flag.String("upload", "", `Destination to upload the archive (usually "gethstore/builds")`)
|
||||||
|
)
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
env := build.Env()
|
||||||
|
|
||||||
|
// Build the Android archive and Maven resources
|
||||||
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||||
|
build.MustRun(gomobileTool("init"))
|
||||||
|
build.MustRun(gomobileTool("bind", "--target", "android", "--javapkg", "org.ethereum", "-v", "github.com/ethereum/go-ethereum/mobile"))
|
||||||
|
|
||||||
|
meta := newMavenMetadata(env)
|
||||||
|
build.Render("build/mvn.pom", meta.Package+".pom", 0755, meta)
|
||||||
|
|
||||||
|
// Skip Maven deploy and Azure upload for PR builds
|
||||||
|
maybeSkipArchive(env)
|
||||||
|
|
||||||
|
// Sign and upload all the artifacts to Maven Central
|
||||||
|
os.Rename("geth.aar", meta.Package+".aar")
|
||||||
|
if *signer != "" && *deploy != "" {
|
||||||
|
// Import the signing key into the local GPG instance
|
||||||
|
if b64key := os.Getenv(*signer); b64key != "" {
|
||||||
|
key, err := base64.StdEncoding.DecodeString(b64key)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("invalid base64 %s", *signer)
|
||||||
|
}
|
||||||
|
gpg := exec.Command("gpg", "--import")
|
||||||
|
gpg.Stdin = bytes.NewReader(key)
|
||||||
|
build.MustRun(gpg)
|
||||||
|
}
|
||||||
|
// Upload the artifacts to Sonatype and/or Maven Central
|
||||||
|
repo := *deploy + "/service/local/staging/deploy/maven2"
|
||||||
|
if meta.Develop {
|
||||||
|
repo = *deploy + "/content/repositories/snapshots"
|
||||||
|
}
|
||||||
|
build.MustRunCommand("mvn", "gpg:sign-and-deploy-file",
|
||||||
|
"-settings=build/mvn.settings", "-Durl="+repo, "-DrepositoryId=ossrh",
|
||||||
|
"-DpomFile="+meta.Package+".pom", "-Dfile="+meta.Package+".aar")
|
||||||
|
}
|
||||||
|
// Sign and upload the archive to Azure
|
||||||
|
archive := "geth-" + archiveBasename("android", env) + ".aar"
|
||||||
|
os.Rename(meta.Package+".aar", archive)
|
||||||
|
|
||||||
|
if err := archiveUpload(archive, *upload, *signer); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func gomobileTool(subcmd string, args ...string) *exec.Cmd {
|
||||||
|
cmd := exec.Command(filepath.Join(GOBIN, "gomobile"), subcmd)
|
||||||
|
cmd.Args = append(cmd.Args, args...)
|
||||||
|
cmd.Env = []string{
|
||||||
|
"GOPATH=" + build.GOPATH(),
|
||||||
|
}
|
||||||
|
for _, e := range os.Environ() {
|
||||||
|
if strings.HasPrefix(e, "GOPATH=") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
cmd.Env = append(cmd.Env, e)
|
||||||
|
}
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type mavenMetadata struct {
|
||||||
|
Version string
|
||||||
|
Package string
|
||||||
|
Develop bool
|
||||||
|
Contributors []mavenContributor
|
||||||
|
}
|
||||||
|
|
||||||
|
type mavenContributor struct {
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMavenMetadata(env build.Environment) mavenMetadata {
|
||||||
|
// Collect the list of authors from the repo root
|
||||||
|
contribs := []mavenContributor{}
|
||||||
|
if authors, err := os.Open("AUTHORS"); err == nil {
|
||||||
|
defer authors.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(authors)
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Skip any whitespace from the authors list
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Split the author and insert as a contributor
|
||||||
|
re := regexp.MustCompile("([^<]+) <(.+>)")
|
||||||
|
parts := re.FindStringSubmatch(line)
|
||||||
|
if len(parts) == 3 {
|
||||||
|
contribs = append(contribs, mavenContributor{Name: parts[1], Email: parts[2]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Render the version and package strings
|
||||||
|
version := build.VERSION()
|
||||||
|
if isUnstableBuild(env) {
|
||||||
|
version += "-SNAPSHOT"
|
||||||
|
}
|
||||||
|
return mavenMetadata{
|
||||||
|
Version: version,
|
||||||
|
Package: "geth-" + version,
|
||||||
|
Develop: isUnstableBuild(env),
|
||||||
|
Contributors: contribs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// XCode frameworks
|
||||||
|
|
||||||
|
func doXCodeFramework(cmdline []string) {
|
||||||
|
var (
|
||||||
|
signer = flag.String("signer", "", `Environment variable holding the signing key (e.g. IOS_SIGNING_KEY)`)
|
||||||
|
deploy = flag.String("deploy", "", `Destination to deploy the archive (usually "trunk")`)
|
||||||
|
upload = flag.String("upload", "", `Destination to upload the archives (usually "gethstore/builds")`)
|
||||||
|
)
|
||||||
|
flag.CommandLine.Parse(cmdline)
|
||||||
|
env := build.Env()
|
||||||
|
|
||||||
|
// Build the iOS XCode framework
|
||||||
|
build.MustRun(goTool("get", "golang.org/x/mobile/cmd/gomobile"))
|
||||||
|
build.MustRun(gomobileTool("init"))
|
||||||
|
|
||||||
|
archive := "geth-" + archiveBasename("ios", env)
|
||||||
|
if err := os.Mkdir(archive, os.ModePerm); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
bind := gomobileTool("bind", "--target", "ios", "--tags", "ios", "--prefix", "GE", "-v", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
bind.Dir, _ = filepath.Abs(archive)
|
||||||
|
build.MustRun(bind)
|
||||||
|
build.MustRunCommand("tar", "-zcvf", archive+".tar.gz", archive)
|
||||||
|
|
||||||
|
// Skip CocoaPods deploy and Azure upload for PR builds
|
||||||
|
maybeSkipArchive(env)
|
||||||
|
|
||||||
|
// Sign and upload the framework to Azure
|
||||||
|
if err := archiveUpload(archive+".tar.gz", *upload, *signer); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
// Prepare and upload a PodSpec to CocoaPods
|
||||||
|
if *deploy != "" {
|
||||||
|
meta := newPodMetadata(env)
|
||||||
|
build.Render("build/pod.podspec", meta.Name+".podspec", 0755, meta)
|
||||||
|
build.MustRunCommand("pod", *deploy, "push", meta.Name+".podspec", "--allow-warnings")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type podMetadata struct {
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
Commit string
|
||||||
|
Contributors []podContributor
|
||||||
|
}
|
||||||
|
|
||||||
|
type podContributor struct {
|
||||||
|
Name string
|
||||||
|
Email string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newPodMetadata(env build.Environment) podMetadata {
|
||||||
|
// Collect the list of authors from the repo root
|
||||||
|
contribs := []podContributor{}
|
||||||
|
if authors, err := os.Open("AUTHORS"); err == nil {
|
||||||
|
defer authors.Close()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(authors)
|
||||||
|
for scanner.Scan() {
|
||||||
|
// Skip any whitespace from the authors list
|
||||||
|
line := strings.TrimSpace(scanner.Text())
|
||||||
|
if line == "" || line[0] == '#' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// Split the author and insert as a contributor
|
||||||
|
re := regexp.MustCompile("([^<]+) <(.+>)")
|
||||||
|
parts := re.FindStringSubmatch(line)
|
||||||
|
if len(parts) == 3 {
|
||||||
|
contribs = append(contribs, podContributor{Name: parts[1], Email: parts[2]})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
name := "Geth"
|
||||||
|
if isUnstableBuild(env) {
|
||||||
|
name += "Develop"
|
||||||
|
}
|
||||||
|
return podMetadata{
|
||||||
|
Name: name,
|
||||||
|
Version: archiveVersion(env),
|
||||||
|
Commit: env.Commit,
|
||||||
|
Contributors: contribs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Cross compilation
|
// Cross compilation
|
||||||
|
|
||||||
func doXgo(cmdline []string) {
|
func doXgo(cmdline []string) {
|
||||||
|
|
|
||||||
57
build/mvn.pom
Normal file
57
build/mvn.pom
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||||
|
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<groupId>org.ethereum</groupId>
|
||||||
|
<artifactId>geth</artifactId>
|
||||||
|
<version>{{.Version}}</version>
|
||||||
|
<packaging>aar</packaging>
|
||||||
|
|
||||||
|
<name>Android Ethereum Client</name>
|
||||||
|
<description>Android port of the go-ethereum libraries and node</description>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
|
<inceptionYear>2015</inceptionYear>
|
||||||
|
|
||||||
|
<licenses>
|
||||||
|
<license>
|
||||||
|
<name>GNU Lesser General Public License, Version 3.0</name>
|
||||||
|
<url>https://www.gnu.org/licenses/lgpl-3.0.en.html</url>
|
||||||
|
<distribution>repo</distribution>
|
||||||
|
</license>
|
||||||
|
</licenses>
|
||||||
|
|
||||||
|
<organization>
|
||||||
|
<name>Ethereum</name>
|
||||||
|
<url>https://ethereum.org</url>
|
||||||
|
</organization>
|
||||||
|
|
||||||
|
<developers>
|
||||||
|
<developer>
|
||||||
|
<id>karalabe</id>
|
||||||
|
<name>Péter Szilágyi</name>
|
||||||
|
<email>peterke@gmail.com</email>
|
||||||
|
<url>https://github.com/karalabe</url>
|
||||||
|
<properties>
|
||||||
|
<picUrl>https://www.gravatar.com/avatar/2ecbf0f5b4b79eebf8c193e5d324357f?s=256</picUrl>
|
||||||
|
</properties>
|
||||||
|
</developer>
|
||||||
|
</developers>
|
||||||
|
|
||||||
|
<contributors>{{range .Contributors}}
|
||||||
|
<contributor>
|
||||||
|
<name>{{.Name}}</name>
|
||||||
|
<email>{{.Email}}</email>
|
||||||
|
</contributor>{{end}}
|
||||||
|
</contributors>
|
||||||
|
|
||||||
|
<issueManagement>
|
||||||
|
<system>GitHub Issues</system>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum/issues/</url>
|
||||||
|
</issueManagement>
|
||||||
|
|
||||||
|
<scm>
|
||||||
|
<url>https://github.com/ethereum/go-ethereum</url>
|
||||||
|
</scm>
|
||||||
|
</project>
|
||||||
24
build/mvn.settings
Normal file
24
build/mvn.settings
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
|
||||||
|
http://maven.apache.org/xsd/settings-1.0.0.xsd">
|
||||||
|
<servers>
|
||||||
|
<server>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<username>${env.ANDROID_SONATYPE_USERNAME}</username>
|
||||||
|
<password>${env.ANDROID_SONATYPE_PASSWORD}</password>
|
||||||
|
</server>
|
||||||
|
</servers>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>ossrh</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>true</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<gpg.executable>gpg</gpg.executable>
|
||||||
|
<gpg.passphrase></gpg.passphrase>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</settings>
|
||||||
22
build/pod.podspec
Normal file
22
build/pod.podspec
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
Pod::Spec.new do |spec|
|
||||||
|
spec.name = '{{.Name}}'
|
||||||
|
spec.version = '{{.Version}}'
|
||||||
|
spec.license = { :type => 'GNU Lesser General Public License, Version 3.0' }
|
||||||
|
spec.homepage = 'https://github.com/ethereum/go-ethereum'
|
||||||
|
spec.authors = { {{range .Contributors}}
|
||||||
|
'{{.Name}}' => '{{.Email}}',{{end}}
|
||||||
|
}
|
||||||
|
spec.summary = 'iOS Ethereum Client'
|
||||||
|
spec.source = { :git => 'https://github.com/ethereum/go-ethereum.git', :commit => '{{.Commit}}' }
|
||||||
|
|
||||||
|
spec.platform = :ios
|
||||||
|
spec.ios.deployment_target = '9.0'
|
||||||
|
spec.ios.vendored_frameworks = 'Frameworks/Geth.framework'
|
||||||
|
|
||||||
|
spec.prepare_command = <<-CMD
|
||||||
|
curl https://gethstore.blob.core.windows.net/builds/geth-ios-all-{{.Version}}.tar.gz | tar -xvz
|
||||||
|
mkdir Frameworks
|
||||||
|
mv geth-ios-all-{{.Version}}/Geth.framework Frameworks
|
||||||
|
rm -rf geth-ios-all-{{.Version}}
|
||||||
|
CMD
|
||||||
|
end
|
||||||
|
|
@ -31,14 +31,15 @@ import (
|
||||||
var (
|
var (
|
||||||
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
|
abiFlag = flag.String("abi", "", "Path to the Ethereum contract ABI json to bind")
|
||||||
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
|
binFlag = flag.String("bin", "", "Path to the Ethereum contract bytecode (generate deploy method)")
|
||||||
typFlag = flag.String("type", "", "Go struct name for the binding (default = package name)")
|
typFlag = flag.String("type", "", "Struct name for the binding (default = package name)")
|
||||||
|
|
||||||
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
|
solFlag = flag.String("sol", "", "Path to the Ethereum contract Solidity source to build and bind")
|
||||||
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
|
solcFlag = flag.String("solc", "solc", "Solidity compiler to use if source builds are requested")
|
||||||
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
|
excFlag = flag.String("exc", "", "Comma separated types to exclude from binding")
|
||||||
|
|
||||||
pkgFlag = flag.String("pkg", "", "Go package name to generate the binding into")
|
pkgFlag = flag.String("pkg", "", "Package name to generate the binding into")
|
||||||
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
|
outFlag = flag.String("out", "", "Output file for the generated binding (default = stdout)")
|
||||||
|
langFlag = flag.String("lang", "go", "Destination language for the bindings (go, java, objc)")
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
@ -53,7 +54,19 @@ func main() {
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
if *pkgFlag == "" {
|
if *pkgFlag == "" {
|
||||||
fmt.Printf("No destination Go package specified (--pkg)\n")
|
fmt.Printf("No destination package specified (--pkg)\n")
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
var lang bind.Lang
|
||||||
|
switch *langFlag {
|
||||||
|
case "go":
|
||||||
|
lang = bind.LangGo
|
||||||
|
case "java":
|
||||||
|
lang = bind.LangJava
|
||||||
|
case "objc":
|
||||||
|
lang = bind.LangObjC
|
||||||
|
default:
|
||||||
|
fmt.Printf("Unsupported destination language \"%s\" (--lang)\n", *langFlag)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
}
|
}
|
||||||
// If the entire solidity code was specified, build and bind based on that
|
// If the entire solidity code was specified, build and bind based on that
|
||||||
|
|
@ -108,7 +121,7 @@ func main() {
|
||||||
types = append(types, kind)
|
types = append(types, kind)
|
||||||
}
|
}
|
||||||
// Generate the contract binding
|
// Generate the contract binding
|
||||||
code, err := bind.Bind(types, abis, bins, *pkgFlag)
|
code, err := bind.Bind(types, abis, bins, *pkgFlag, lang)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("Failed to generate ABI binding: %v\n", err)
|
fmt.Printf("Failed to generate ABI binding: %v\n", err)
|
||||||
os.Exit(-1)
|
os.Exit(-1)
|
||||||
|
|
|
||||||
|
|
@ -76,10 +76,11 @@ func runTestWithReader(test string, r io.Reader) error {
|
||||||
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
|
case "bk", "block", "blocktest", "blockchaintest", "blocktests", "blockchaintests":
|
||||||
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests)
|
err = tests.RunBlockTestWithReader(params.MainNetHomesteadBlock, params.MainNetDAOForkBlock, params.MainNetHomesteadGasRepriceBlock, r, skipTests)
|
||||||
case "st", "state", "statetest", "statetests":
|
case "st", "state", "statetest", "statetests":
|
||||||
rs := tests.RuleSet{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true}
|
rs := ¶ms.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true, EIP150Block: params.MainNetHomesteadGasRepriceBlock}
|
||||||
err = tests.RunStateTestWithReader(rs, r, skipTests)
|
err = tests.RunStateTestWithReader(rs, r, skipTests)
|
||||||
case "tx", "transactiontest", "transactiontests":
|
case "tx", "transactiontest", "transactiontests":
|
||||||
err = tests.RunTransactionTestsWithReader(r, skipTests)
|
rs := ¶ms.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock, DAOForkBlock: params.MainNetDAOForkBlock, DAOForkSupport: true, EIP150Block: params.MainNetHomesteadGasRepriceBlock}
|
||||||
|
err = tests.RunTransactionTestsWithReader(rs, r, skipTests)
|
||||||
case "vm", "vmtest", "vmtests":
|
case "vm", "vmtest", "vmtests":
|
||||||
err = tests.RunVmTestWithReader(r, skipTests)
|
err = tests.RunVmTestWithReader(r, skipTests)
|
||||||
case "rlp", "rlptest", "rlptests":
|
case "rlp", "rlptest", "rlptests":
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ func run(ctx *cli.Context) error {
|
||||||
vmdone := time.Since(tstart)
|
vmdone := time.Since(tstart)
|
||||||
|
|
||||||
if ctx.GlobalBool(DumpFlag.Name) {
|
if ctx.GlobalBool(DumpFlag.Name) {
|
||||||
statedb.Commit()
|
statedb.Commit(true)
|
||||||
fmt.Println(string(statedb.Dump()))
|
fmt.Println(string(statedb.Dump()))
|
||||||
}
|
}
|
||||||
vm.StdErrFormat(logger.StructLogs())
|
vm.StdErrFormat(logger.StructLogs())
|
||||||
|
|
@ -251,7 +251,7 @@ func NewEnv(state *state.StateDB, transactor common.Address, value *big.Int, cfg
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
// ruleSet implements vm.RuleSet and will always default to the homestead rule set.
|
// ruleSet implements vm.ChainConfig and will always default to the homestead rule set.
|
||||||
type ruleSet struct{}
|
type ruleSet struct{}
|
||||||
|
|
||||||
func (ruleSet) IsHomestead(*big.Int) bool { return true }
|
func (ruleSet) IsHomestead(*big.Int) bool { return true }
|
||||||
|
|
@ -259,22 +259,22 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
|
||||||
return params.GasTableHomesteadGasRepriceFork
|
return params.GasTableHomesteadGasRepriceFork
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) RuleSet() vm.RuleSet { return ruleSet{} }
|
func (self *VMEnv) ChainConfig() *params.ChainConfig { return params.TestChainConfig }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
func (self *VMEnv) Db() vm.Database { return self.state }
|
func (self *VMEnv) Db() vm.Database { return self.state }
|
||||||
func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() }
|
func (self *VMEnv) SnapshotDatabase() int { return self.state.Snapshot() }
|
||||||
func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
|
func (self *VMEnv) RevertToSnapshot(snap int) { self.state.RevertToSnapshot(snap) }
|
||||||
func (self *VMEnv) Origin() common.Address { return *self.transactor }
|
func (self *VMEnv) Origin() common.Address { return *self.transactor }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
|
func (self *VMEnv) BlockNumber() *big.Int { return common.Big0 }
|
||||||
func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
|
func (self *VMEnv) Coinbase() common.Address { return *self.transactor }
|
||||||
func (self *VMEnv) Time() *big.Int { return self.time }
|
func (self *VMEnv) Time() *big.Int { return self.time }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
|
func (self *VMEnv) Difficulty() *big.Int { return common.Big1 }
|
||||||
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
|
func (self *VMEnv) BlockHash() []byte { return make([]byte, 32) }
|
||||||
func (self *VMEnv) Value() *big.Int { return self.value }
|
func (self *VMEnv) Value() *big.Int { return self.value }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
|
func (self *VMEnv) GasLimit() *big.Int { return big.NewInt(1000000000) }
|
||||||
func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy }
|
func (self *VMEnv) VmType() vm.Type { return vm.StdVmTy }
|
||||||
func (self *VMEnv) Depth() int { return 0 }
|
func (self *VMEnv) Depth() int { return 0 }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
||||||
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
|
if self.block.Number().Cmp(big.NewInt(int64(n))) == 0 {
|
||||||
return self.block.Hash()
|
return self.block.Hash()
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
|
@ -122,7 +121,7 @@ func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) {
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
TestGenesisState: db,
|
TestGenesisState: db,
|
||||||
TestGenesisBlock: test.Genesis,
|
TestGenesisBlock: test.Genesis,
|
||||||
ChainConfig: &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
|
ChainConfig: ¶ms.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
|
||||||
}
|
}
|
||||||
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
|
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum 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 General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package utils
|
|
||||||
|
|
||||||
import "github.com/ethereum/go-ethereum/p2p/discover"
|
|
||||||
|
|
||||||
// FrontierBootNodes are the enode URLs of the P2P bootstrap nodes running on
|
|
||||||
// the Frontier network.
|
|
||||||
var FrontierBootNodes = []*discover.Node{
|
|
||||||
// ETH/DEV Go Bootnodes
|
|
||||||
discover.MustParseNode("enode://a979fb575495b8d6db44f750317d0f4622bf4c2aa3365d6af7c284339968eef29b69ad0dce72a4d8db5ebb4968de0e3bec910127f134779fbcb0cb6d3331163c@52.16.188.185:30303"), // IE
|
|
||||||
discover.MustParseNode("enode://de471bccee3d042261d52e9bff31458daecc406142b401d4cd848f677479f73104b9fdeb090af9583d3391b7f10cb2ba9e26865dd5fca4fcdc0fb1e3b723c786@54.94.239.50:30303"), // BR
|
|
||||||
discover.MustParseNode("enode://1118980bf48b0a3640bdba04e0fe78b1add18e1cd99bf22d53daac1fd9972ad650df52176e7c7d89d1114cfef2bc23a2959aa54998a46afcf7d91809f0855082@52.74.57.123:30303"), // SG
|
|
||||||
|
|
||||||
// ETH/DEV Cpp Bootnodes
|
|
||||||
discover.MustParseNode("enode://979b7fa28feeb35a4741660a16076f1943202cb72b6af70d327f053e248bab9ba81760f39d0701ef1d8f89cc1fbd2cacba0710a12cd5314d5e0c9021aa3637f9@5.1.83.226:30303"),
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestNetBootNodes are the enode URLs of the P2P bootstrap nodes running on the
|
|
||||||
// Morden test network.
|
|
||||||
var TestNetBootNodes = []*discover.Node{
|
|
||||||
// ETH/DEV Go Bootnodes
|
|
||||||
discover.MustParseNode("enode://e4533109cc9bd7604e4ff6c095f7a1d807e15b38e9bfeb05d3b7c423ba86af0a9e89abbf40bd9dde4250fef114cd09270fa4e224cbeef8b7bf05a51e8260d6b8@94.242.229.4:40404"),
|
|
||||||
discover.MustParseNode("enode://8c336ee6f03e99613ad21274f269479bf4413fb294d697ef15ab897598afb931f56beb8e97af530aee20ce2bcba5776f4a312bc168545de4d43736992c814592@94.242.229.203:30303"),
|
|
||||||
|
|
||||||
// ETH/DEV Cpp Bootnodes
|
|
||||||
}
|
|
||||||
|
|
@ -46,6 +46,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
"github.com/ethereum/go-ethereum/p2p/nat"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
|
|
@ -487,9 +488,9 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||||
// Return pre-configured nodes if none were manually requested
|
// Return pre-configured nodes if none were manually requested
|
||||||
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
return TestNetBootNodes
|
return params.TestnetBootnodes
|
||||||
}
|
}
|
||||||
return FrontierBootNodes
|
return params.MainnetBootnodes
|
||||||
}
|
}
|
||||||
// Otherwise parse and use the CLI bootstrap nodes
|
// Otherwise parse and use the CLI bootstrap nodes
|
||||||
bootnodes := []*discover.Node{}
|
bootnodes := []*discover.Node{}
|
||||||
|
|
@ -505,13 +506,36 @@ func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node {
|
||||||
return bootnodes
|
return bootnodes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line
|
||||||
|
// flags, reverting to pre-configured ones if none have been specified.
|
||||||
|
func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node {
|
||||||
|
// Return pre-configured nodes if none were manually requested
|
||||||
|
if !ctx.GlobalIsSet(BootnodesFlag.Name) {
|
||||||
|
return params.DiscoveryV5Bootnodes
|
||||||
|
}
|
||||||
|
// Otherwise parse and use the CLI bootstrap nodes
|
||||||
|
bootnodes := []*discv5.Node{}
|
||||||
|
|
||||||
|
for _, url := range strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") {
|
||||||
|
node, err := discv5.ParseNode(url)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(logger.Error).Infof("Bootstrap URL %s: %v\n", url, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bootnodes = append(bootnodes, node)
|
||||||
|
}
|
||||||
|
return bootnodes
|
||||||
|
}
|
||||||
|
|
||||||
// MakeListenAddress creates a TCP listening address string from set command
|
// MakeListenAddress creates a TCP listening address string from set command
|
||||||
// line flags.
|
// line flags.
|
||||||
func MakeListenAddress(ctx *cli.Context) string {
|
func MakeListenAddress(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeListenAddressV5(ctx *cli.Context) string {
|
// MakeDiscoveryV5Address creates a UDP listening address string from set command
|
||||||
|
// line flags for the V5 discovery protocol.
|
||||||
|
func MakeDiscoveryV5Address(ctx *cli.Context) string {
|
||||||
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -647,9 +671,10 @@ func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node {
|
||||||
UserIdent: makeNodeUserIdent(ctx),
|
UserIdent: makeNodeUserIdent(ctx),
|
||||||
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name),
|
||||||
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0,
|
||||||
|
DiscoveryV5Addr: MakeDiscoveryV5Address(ctx),
|
||||||
BootstrapNodes: MakeBootstrapNodes(ctx),
|
BootstrapNodes: MakeBootstrapNodes(ctx),
|
||||||
|
BootstrapNodesV5: MakeBootstrapNodesV5(ctx),
|
||||||
ListenAddr: MakeListenAddress(ctx),
|
ListenAddr: MakeListenAddress(ctx),
|
||||||
ListenAddrV5: MakeListenAddressV5(ctx),
|
|
||||||
NAT: MakeNAT(ctx),
|
NAT: MakeNAT(ctx),
|
||||||
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
|
||||||
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
|
||||||
|
|
@ -801,7 +826,7 @@ func SetupNetwork(ctx *cli.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
|
// MakeChainConfig reads the chain configuration from the database in ctx.Datadir.
|
||||||
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig {
|
func MakeChainConfig(ctx *cli.Context, stack *node.Node) *params.ChainConfig {
|
||||||
db := MakeChainDatabase(ctx, stack)
|
db := MakeChainDatabase(ctx, stack)
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
|
|
@ -809,9 +834,9 @@ func MakeChainConfig(ctx *cli.Context, stack *node.Node) *core.ChainConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeChainConfigFromDb reads the chain configuration from the given database.
|
// MakeChainConfigFromDb reads the chain configuration from the given database.
|
||||||
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfig {
|
func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *params.ChainConfig {
|
||||||
// If the chain is already initialized, use any existing chain configs
|
// If the chain is already initialized, use any existing chain configs
|
||||||
config := new(core.ChainConfig)
|
config := new(params.ChainConfig)
|
||||||
|
|
||||||
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
|
genesis := core.GetBlock(db, core.GetCanonicalHash(db, 0), 0)
|
||||||
if genesis != nil {
|
if genesis != nil {
|
||||||
|
|
@ -825,6 +850,10 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfi
|
||||||
Fatalf("Could not make chain configuration: %v", err)
|
Fatalf("Could not make chain configuration: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// set chain id in case it's zero.
|
||||||
|
if config.ChainId == nil {
|
||||||
|
config.ChainId = new(big.Int)
|
||||||
|
}
|
||||||
// Check whether we are allowed to set default config params or not:
|
// Check whether we are allowed to set default config params or not:
|
||||||
// - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
|
// - If no genesis is set, we're running either mainnet or testnet (private nets use `geth init`)
|
||||||
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
|
// - If a genesis is already set, ensure we have a configuration for it (mainnet or testnet)
|
||||||
|
|
@ -849,21 +878,44 @@ func MakeChainConfigFromDb(ctx *cli.Context, db ethdb.Database) *core.ChainConfi
|
||||||
}
|
}
|
||||||
config.DAOForkSupport = true
|
config.DAOForkSupport = true
|
||||||
}
|
}
|
||||||
if config.HomesteadGasRepriceBlock == nil {
|
if config.EIP150Block == nil {
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
config.HomesteadGasRepriceBlock = params.TestNetHomesteadGasRepriceBlock
|
config.EIP150Block = params.TestNetHomesteadGasRepriceBlock
|
||||||
} else {
|
} else {
|
||||||
config.HomesteadGasRepriceBlock = params.MainNetHomesteadGasRepriceBlock
|
config.EIP150Block = params.MainNetHomesteadGasRepriceBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.HomesteadGasRepriceHash == (common.Hash{}) {
|
if config.EIP150Hash == (common.Hash{}) {
|
||||||
if ctx.GlobalBool(TestNetFlag.Name) {
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
config.HomesteadGasRepriceHash = params.TestNetHomesteadGasRepriceHash
|
config.EIP150Hash = params.TestNetHomesteadGasRepriceHash
|
||||||
} else {
|
} else {
|
||||||
config.HomesteadGasRepriceHash = params.MainNetHomesteadGasRepriceHash
|
config.EIP150Hash = params.MainNetHomesteadGasRepriceHash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if config.EIP155Block == nil {
|
||||||
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
|
config.EIP150Block = params.TestNetSpuriousDragon
|
||||||
|
} else {
|
||||||
|
config.EIP155Block = params.MainNetSpuriousDragon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.EIP158Block == nil {
|
||||||
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
|
config.EIP158Block = params.TestNetSpuriousDragon
|
||||||
|
} else {
|
||||||
|
config.EIP158Block = params.MainNetSpuriousDragon
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if config.ChainId.BitLen() == 0 {
|
||||||
|
if ctx.GlobalBool(TestNetFlag.Name) {
|
||||||
|
config.ChainId = params.TestNetChainID
|
||||||
|
} else {
|
||||||
|
config.ChainId = params.MainNetChainID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
config.DAOForkSupport = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Force override any existing configs if explicitly requested
|
// Force override any existing configs if explicitly requested
|
||||||
switch {
|
switch {
|
||||||
case ctx.GlobalBool(SupportDAOFork.Name):
|
case ctx.GlobalBool(SupportDAOFork.Name):
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,12 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// registryAPIBackend is a backend for an Ethereum Registry.
|
// registryAPIBackend is a backend for an Ethereum Registry.
|
||||||
type registryAPIBackend struct {
|
type registryAPIBackend struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
bc *core.BlockChain
|
bc *core.BlockChain
|
||||||
chainDb ethdb.Database
|
chainDb ethdb.Database
|
||||||
txPool *core.TxPool
|
txPool *core.TxPool
|
||||||
|
|
@ -45,12 +46,12 @@ type registryAPIBackend struct {
|
||||||
|
|
||||||
// PrivateRegistarAPI offers various functions to access the Ethereum registry.
|
// PrivateRegistarAPI offers various functions to access the Ethereum registry.
|
||||||
type PrivateRegistarAPI struct {
|
type PrivateRegistarAPI struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
be *registryAPIBackend
|
be *registryAPIBackend
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
|
// NewPrivateRegistarAPI creates a new PrivateRegistarAPI instance.
|
||||||
func NewPrivateRegistarAPI(config *core.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
|
func NewPrivateRegistarAPI(config *params.ChainConfig, bc *core.BlockChain, chainDb ethdb.Database, txPool *core.TxPool, am *accounts.Manager) *PrivateRegistarAPI {
|
||||||
return &PrivateRegistarAPI{
|
return &PrivateRegistarAPI{
|
||||||
config: config,
|
config: config,
|
||||||
be: ®istryAPIBackend{
|
be: ®istryAPIBackend{
|
||||||
|
|
@ -173,25 +174,20 @@ func (be *registryAPIBackend) Call(fromStr, toStr, valueStr, gasStr, gasPriceStr
|
||||||
|
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
||||||
msg := callmsg{
|
var to *common.Address
|
||||||
from: from,
|
|
||||||
gas: common.Big(gasStr),
|
|
||||||
gasPrice: common.Big(gasPriceStr),
|
|
||||||
value: common.Big(valueStr),
|
|
||||||
data: common.FromHex(dataStr),
|
|
||||||
}
|
|
||||||
if len(toStr) > 0 {
|
if len(toStr) > 0 {
|
||||||
addr := common.HexToAddress(toStr)
|
addr := common.HexToAddress(toStr)
|
||||||
msg.to = &addr
|
to = &addr
|
||||||
}
|
}
|
||||||
|
gas := common.Big(gasStr)
|
||||||
if msg.gas.Cmp(big.NewInt(0)) == 0 {
|
if gas.BitLen() == 0 {
|
||||||
msg.gas = big.NewInt(50000000)
|
gas = big.NewInt(50000000)
|
||||||
}
|
}
|
||||||
|
gasPrice := common.Big(gasPriceStr)
|
||||||
if msg.gasPrice.Cmp(big.NewInt(0)) == 0 {
|
if gasPrice.BitLen() == 0 {
|
||||||
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||||
}
|
}
|
||||||
|
msg := types.NewMessage(from.Address(), to, 0, common.Big(valueStr), gas, gasPrice, common.FromHex(dataStr), false)
|
||||||
|
|
||||||
header := be.bc.CurrentBlock().Header()
|
header := be.bc.CurrentBlock().Header()
|
||||||
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
|
vmenv := core.NewEnv(statedb, be.config, be.bc, msg, header, vm.Config{})
|
||||||
|
|
@ -257,11 +253,12 @@ func (be *registryAPIBackend) Transact(fromStr, toStr, nonceStr, valueStr, gasSt
|
||||||
tx = types.NewTransaction(nonce, to, value, gas, price, data)
|
tx = types.NewTransaction(nonce, to, value, gas, price, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
signature, err := be.am.SignEthereum(from, tx.SigHash().Bytes())
|
sigHash := (types.HomesteadSigner{}).Hash(tx)
|
||||||
|
signature, err := be.am.SignEthereum(from, sigHash.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
signedTx, err := tx.WithSignature(signature)
|
signedTx, err := tx.WithSignature(types.HomesteadSigner{}, signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,10 @@ const (
|
||||||
var hashJsonLengthErr = errors.New("common: unmarshalJSON failed: hash must be exactly 32 bytes")
|
var hashJsonLengthErr = errors.New("common: unmarshalJSON failed: hash must be exactly 32 bytes")
|
||||||
|
|
||||||
type (
|
type (
|
||||||
Hash [HashLength]byte
|
// Hash represents the 32 byte Keccak256 hash of arbitrary data.
|
||||||
|
Hash [HashLength]byte
|
||||||
|
|
||||||
|
// Address represents the 20 byte address of an Ethereum account.
|
||||||
Address [AddressLength]byte
|
Address [AddressLength]byte
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,10 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/internal/jsre"
|
"github.com/ethereum/go-ethereum/internal/jsre"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -97,7 +97,7 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
|
||||||
t.Fatalf("failed to create node: %v", err)
|
t.Fatalf("failed to create node: %v", err)
|
||||||
}
|
}
|
||||||
ethConf := ð.Config{
|
ethConf := ð.Config{
|
||||||
ChainConfig: &core.ChainConfig{HomesteadBlock: new(big.Int)},
|
ChainConfig: ¶ms.ChainConfig{HomesteadBlock: new(big.Int), ChainId: new(big.Int)},
|
||||||
Etherbase: common.HexToAddress(testAddress),
|
Etherbase: common.HexToAddress(testAddress),
|
||||||
PowTest: true,
|
PowTest: true,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) {
|
||||||
toaddr := common.Address{}
|
toaddr := common.Address{}
|
||||||
data := make([]byte, nbytes)
|
data := make([]byte, nbytes)
|
||||||
gas := IntrinsicGas(data, false, false)
|
gas := IntrinsicGas(data, false, false)
|
||||||
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(benchRootKey)
|
tx, _ := types.NewTransaction(gen.TxNonce(benchRootAddr), toaddr, big.NewInt(1), gas, nil, data).SignECDSA(types.HomesteadSigner{}, benchRootKey)
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -123,7 +123,7 @@ func genTxRing(naccounts int) func(int, *BlockGen) {
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
tx, _ = tx.SignECDSA(ringKeys[from])
|
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, ringKeys[from])
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
from = to
|
from = to
|
||||||
}
|
}
|
||||||
|
|
@ -163,12 +163,12 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) {
|
||||||
// Generate a chain of b.N blocks using the supplied block
|
// Generate a chain of b.N blocks using the supplied block
|
||||||
// generator function.
|
// generator function.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
|
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{benchRootAddr, benchRootFunds})
|
||||||
chain, _ := GenerateChain(nil, genesis, db, b.N, gen)
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, b.N, gen)
|
||||||
|
|
||||||
// Time the insertion of the new chain.
|
// Time the insertion of the new chain.
|
||||||
// State and blocks are stored in the same DB.
|
// State and blocks are stored in the same DB.
|
||||||
evmux := new(event.TypeMux)
|
evmux := new(event.TypeMux)
|
||||||
chainman, _ := NewBlockChain(db, &ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux)
|
chainman, _ := NewBlockChain(db, ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}, FakePow{}, evmux)
|
||||||
defer chainman.Stop()
|
defer chainman.Stop()
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
|
||||||
|
|
@ -41,13 +41,13 @@ var (
|
||||||
//
|
//
|
||||||
// BlockValidator implements Validator.
|
// BlockValidator implements Validator.
|
||||||
type BlockValidator struct {
|
type BlockValidator struct {
|
||||||
config *ChainConfig // Chain configuration options
|
config *params.ChainConfig // Chain configuration options
|
||||||
bc *BlockChain // Canonical block chain
|
bc *BlockChain // Canonical block chain
|
||||||
Pow pow.PoW // Proof of work used for validating
|
Pow pow.PoW // Proof of work used for validating
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||||
func NewBlockValidator(config *ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
|
func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain, pow pow.PoW) *BlockValidator {
|
||||||
validator := &BlockValidator{
|
validator := &BlockValidator{
|
||||||
config: config,
|
config: config,
|
||||||
Pow: pow,
|
Pow: pow,
|
||||||
|
|
@ -128,7 +128,7 @@ func (v *BlockValidator) ValidateState(block, parent *types.Block, statedb *stat
|
||||||
}
|
}
|
||||||
// Validate the state root against the received state root and throw
|
// Validate the state root against the received state root and throw
|
||||||
// an error if they don't match.
|
// an error if they don't match.
|
||||||
if root := statedb.IntermediateRoot(); header.Root != root {
|
if root := statedb.IntermediateRoot(v.config.IsEIP158(header.Number)); header.Root != root {
|
||||||
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
|
return fmt.Errorf("invalid merkle root: header=%x computed=%x", header.Root, root)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -203,7 +203,7 @@ func (v *BlockValidator) ValidateHeader(header, parent *types.Header, checkPow b
|
||||||
// Validates a header. Returns an error if the header is invalid.
|
// Validates a header. Returns an error if the header is invalid.
|
||||||
//
|
//
|
||||||
// See YP section 4.3.4. "Block Header Validity"
|
// See YP section 4.3.4. "Block Header Validity"
|
||||||
func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
|
func ValidateHeader(config *params.ChainConfig, pow pow.PoW, header *types.Header, parent *types.Header, checkPow, uncle bool) error {
|
||||||
if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
|
if big.NewInt(int64(len(header.Extra))).Cmp(params.MaximumExtraDataSize) == 1 {
|
||||||
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
|
return fmt.Errorf("Header extra data too long (%d)", len(header.Extra))
|
||||||
}
|
}
|
||||||
|
|
@ -251,9 +251,9 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
|
||||||
if err := ValidateDAOHeaderExtraData(config, header); err != nil {
|
if err := ValidateDAOHeaderExtraData(config, header); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if config.HomesteadGasRepriceBlock != nil && config.HomesteadGasRepriceBlock.Cmp(header.Number) == 0 {
|
if config.EIP150Block != nil && config.EIP150Block.Cmp(header.Number) == 0 {
|
||||||
if config.HomesteadGasRepriceHash != (common.Hash{}) && config.HomesteadGasRepriceHash != header.Hash() {
|
if config.EIP150Hash != (common.Hash{}) && config.EIP150Hash != header.Hash() {
|
||||||
return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.HomesteadGasRepriceHash)
|
return ValidationError("Homestead gas reprice fork hash mismatch: have 0x%x, want 0x%x", header.Hash(), config.EIP150Hash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -262,7 +262,7 @@ func ValidateHeader(config *ChainConfig, pow pow.PoW, header *types.Header, pare
|
||||||
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
// CalcDifficulty is the difficulty adjustment algorithm. It returns
|
||||||
// the difficulty that a new block should have when created at time
|
// the difficulty that a new block should have when created at time
|
||||||
// given the parent block's time and difficulty.
|
// given the parent block's time and difficulty.
|
||||||
func CalcDifficulty(config *ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
|
func CalcDifficulty(config *params.ChainConfig, time, parentTime uint64, parentNumber, parentDiff *big.Int) *big.Int {
|
||||||
if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
|
if config.IsHomestead(new(big.Int).Add(parentNumber, common.Big1)) {
|
||||||
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
|
return calcDifficultyHomestead(time, parentTime, parentNumber, parentDiff)
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -27,11 +27,13 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow/ezp"
|
"github.com/ethereum/go-ethereum/pow/ezp"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testChainConfig() *ChainConfig {
|
func testChainConfig() *params.ChainConfig {
|
||||||
return &ChainConfig{HomesteadBlock: big.NewInt(0)}
|
return params.TestChainConfig
|
||||||
|
//return ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
||||||
}
|
}
|
||||||
|
|
||||||
func proc() (Validator, *BlockChain) {
|
func proc() (Validator, *BlockChain) {
|
||||||
|
|
@ -51,15 +53,15 @@ func TestNumber(t *testing.T) {
|
||||||
_, chain := proc()
|
_, chain := proc()
|
||||||
|
|
||||||
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
statedb, _ := state.New(chain.Genesis().Root(), chain.chainDb)
|
||||||
header := makeHeader(chain.Genesis(), statedb)
|
|
||||||
header.Number = big.NewInt(3)
|
|
||||||
cfg := testChainConfig()
|
cfg := testChainConfig()
|
||||||
|
header := makeHeader(cfg, chain.Genesis(), statedb)
|
||||||
|
header.Number = big.NewInt(3)
|
||||||
err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
err := ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
||||||
if err != BlockNumberErr {
|
if err != BlockNumberErr {
|
||||||
t.Errorf("expected block number error, got %q", err)
|
t.Errorf("expected block number error, got %q", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
header = makeHeader(chain.Genesis(), statedb)
|
header = makeHeader(cfg, chain.Genesis(), statedb)
|
||||||
err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
err = ValidateHeader(cfg, pow, header, chain.Genesis().Header(), false, false)
|
||||||
if err == BlockNumberErr {
|
if err == BlockNumberErr {
|
||||||
t.Errorf("didn't expect block number error")
|
t.Errorf("didn't expect block number error")
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
@ -78,7 +79,7 @@ const (
|
||||||
// included in the canonical one where as GetBlockByNumber always represents the
|
// included in the canonical one where as GetBlockByNumber always represents the
|
||||||
// canonical chain.
|
// canonical chain.
|
||||||
type BlockChain struct {
|
type BlockChain struct {
|
||||||
config *ChainConfig // chain & network configuration
|
config *params.ChainConfig // chain & network configuration
|
||||||
|
|
||||||
hc *HeaderChain
|
hc *HeaderChain
|
||||||
chainDb ethdb.Database
|
chainDb ethdb.Database
|
||||||
|
|
@ -113,7 +114,7 @@ type BlockChain struct {
|
||||||
// NewBlockChain returns a fully initialised block chain using information
|
// NewBlockChain returns a fully initialised block chain using information
|
||||||
// available in the database. It initialiser the default Ethereum Validator and
|
// available in the database. It initialiser the default Ethereum Validator and
|
||||||
// Processor.
|
// Processor.
|
||||||
func NewBlockChain(chainDb ethdb.Database, config *ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
|
func NewBlockChain(chainDb ethdb.Database, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*BlockChain, error) {
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||||
blockCache, _ := lru.New(blockCacheLimit)
|
blockCache, _ := lru.New(blockCacheLimit)
|
||||||
|
|
@ -633,17 +634,19 @@ func (self *BlockChain) Rollback(chain []common.Hash) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetReceiptsData computes all the non-consensus fields of the receipts
|
// SetReceiptsData computes all the non-consensus fields of the receipts
|
||||||
func SetReceiptsData(block *types.Block, receipts types.Receipts) {
|
func SetReceiptsData(config *params.ChainConfig, block *types.Block, receipts types.Receipts) {
|
||||||
|
signer := types.MakeSigner(config, block.Number())
|
||||||
|
|
||||||
transactions, logIndex := block.Transactions(), uint(0)
|
transactions, logIndex := block.Transactions(), uint(0)
|
||||||
|
|
||||||
for j := 0; j < len(receipts); j++ {
|
for j := 0; j < len(receipts); j++ {
|
||||||
// The transaction hash can be retrieved from the transaction itself
|
// The transaction hash can be retrieved from the transaction itself
|
||||||
receipts[j].TxHash = transactions[j].Hash()
|
receipts[j].TxHash = transactions[j].Hash()
|
||||||
|
|
||||||
|
tx, _ := transactions[j].AsMessage(signer)
|
||||||
// The contract address can be derived from the transaction itself
|
// The contract address can be derived from the transaction itself
|
||||||
if MessageCreatesContract(transactions[j]) {
|
if MessageCreatesContract(tx) {
|
||||||
from, _ := transactions[j].From()
|
receipts[j].ContractAddress = crypto.CreateAddress(tx.From(), tx.Nonce())
|
||||||
receipts[j].ContractAddress = crypto.CreateAddress(from, transactions[j].Nonce())
|
|
||||||
}
|
}
|
||||||
// The used gas can be calculated based on previous receipts
|
// The used gas can be calculated based on previous receipts
|
||||||
if j == 0 {
|
if j == 0 {
|
||||||
|
|
@ -665,6 +668,7 @@ func SetReceiptsData(block *types.Block, receipts types.Receipts) {
|
||||||
|
|
||||||
// InsertReceiptChain attempts to complete an already existing header chain with
|
// InsertReceiptChain attempts to complete an already existing header chain with
|
||||||
// transaction and receipt data.
|
// transaction and receipt data.
|
||||||
|
// XXX should this be moved to the test?
|
||||||
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain []types.Receipts) (int, error) {
|
||||||
self.wg.Add(1)
|
self.wg.Add(1)
|
||||||
defer self.wg.Done()
|
defer self.wg.Done()
|
||||||
|
|
@ -704,7 +708,7 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Compute all the non-consensus fields of the receipts
|
// Compute all the non-consensus fields of the receipts
|
||||||
SetReceiptsData(block, receipts)
|
SetReceiptsData(self.config, block, receipts)
|
||||||
// Write all the data out into the database
|
// Write all the data out into the database
|
||||||
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
if err := WriteBody(self.chainDb, block.Hash(), block.NumberU64(), block.Body()); err != nil {
|
||||||
errs[index] = fmt.Errorf("failed to write block body: %v", err)
|
errs[index] = fmt.Errorf("failed to write block body: %v", err)
|
||||||
|
|
@ -924,7 +928,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Process block using the parent state as reference point.
|
// Process block using the parent state as reference point.
|
||||||
receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, self.config.VmConfig)
|
receipts, logs, usedGas, err := self.processor.Process(block, self.stateCache, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
reportBlock(block, err)
|
reportBlock(block, err)
|
||||||
return i, err
|
return i, err
|
||||||
|
|
@ -936,7 +940,7 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
// Write state changes to database
|
// Write state changes to database
|
||||||
_, err = self.stateCache.Commit()
|
_, err = self.stateCache.Commit(self.config.IsEIP158(block.Number()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return i, err
|
return i, err
|
||||||
}
|
}
|
||||||
|
|
@ -1309,4 +1313,4 @@ func (self *BlockChain) GetHeaderByNumber(number uint64) *types.Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config retrieves the blockchain's chain configuration.
|
// Config retrieves the blockchain's chain configuration.
|
||||||
func (self *BlockChain) Config() *ChainConfig { return self.config }
|
func (self *BlockChain) Config() *params.ChainConfig { return self.config }
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {
|
||||||
blockchain.mu.Lock()
|
blockchain.mu.Lock()
|
||||||
WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))
|
WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))
|
||||||
WriteBlock(blockchain.chainDb, block)
|
WriteBlock(blockchain.chainDb, block)
|
||||||
statedb.Commit()
|
statedb.Commit(false)
|
||||||
blockchain.mu.Unlock()
|
blockchain.mu.Unlock()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -711,14 +711,15 @@ func TestFastVsFullChains(t *testing.T) {
|
||||||
address = crypto.PubkeyToAddress(key.PublicKey)
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
funds = big.NewInt(1000000000)
|
funds = big.NewInt(1000000000)
|
||||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
genesis = GenesisBlockForTesting(gendb, address, funds)
|
||||||
|
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||||
)
|
)
|
||||||
blocks, receipts := GenerateChain(nil, genesis, gendb, 1024, func(i int, block *BlockGen) {
|
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, 1024, func(i int, block *BlockGen) {
|
||||||
block.SetCoinbase(common.Address{0x00})
|
block.SetCoinbase(common.Address{0x00})
|
||||||
|
|
||||||
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
// If the block number is multiple of 3, send a few bonus transactions to the miner
|
||||||
if i%3 == 2 {
|
if i%3 == 2 {
|
||||||
for j := 0; j < i%4+1; j++ {
|
for j := 0; j < i%4+1; j++ {
|
||||||
tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key)
|
tx, err := types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -795,7 +796,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) {
|
||||||
genesis = GenesisBlockForTesting(gendb, address, funds)
|
genesis = GenesisBlockForTesting(gendb, address, funds)
|
||||||
)
|
)
|
||||||
height := uint64(1024)
|
height := uint64(1024)
|
||||||
blocks, receipts := GenerateChain(nil, genesis, gendb, int(height), nil)
|
blocks, receipts := GenerateChain(params.TestChainConfig, genesis, gendb, int(height), nil)
|
||||||
|
|
||||||
// Configure a subchain to roll back
|
// Configure a subchain to roll back
|
||||||
remove := []common.Hash{}
|
remove := []common.Hash{}
|
||||||
|
|
@ -872,6 +873,7 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||||
)
|
)
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
genesis := WriteGenesisBlockForTesting(db,
|
||||||
GenesisAccount{addr1, big.NewInt(1000000)},
|
GenesisAccount{addr1, big.NewInt(1000000)},
|
||||||
|
|
@ -881,8 +883,8 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
// Create two transactions shared between the chains:
|
// Create two transactions shared between the chains:
|
||||||
// - postponed: transaction included at a later block in the forked chain
|
// - postponed: transaction included at a later block in the forked chain
|
||||||
// - swapped: transaction included at the same block number in the forked chain
|
// - swapped: transaction included at the same block number in the forked chain
|
||||||
postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1)
|
postponed, _ := types.NewTransaction(0, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
||||||
swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1)
|
swapped, _ := types.NewTransaction(1, addr1, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
||||||
|
|
||||||
// Create two transactions that will be dropped by the forked chain:
|
// Create two transactions that will be dropped by the forked chain:
|
||||||
// - pastDrop: transaction dropped retroactively from a past block
|
// - pastDrop: transaction dropped retroactively from a past block
|
||||||
|
|
@ -895,16 +897,16 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
// - futureAdd: transaction added after the reorg has already finished
|
// - futureAdd: transaction added after the reorg has already finished
|
||||||
var pastAdd, freshAdd, futureAdd *types.Transaction
|
var pastAdd, freshAdd, futureAdd *types.Transaction
|
||||||
|
|
||||||
chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
|
pastDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
||||||
|
|
||||||
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
|
gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point
|
||||||
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
|
gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
|
freshDrop, _ = types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
||||||
|
|
||||||
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
|
gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point
|
||||||
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
|
gen.AddTx(swapped) // This transaction will be swapped out at the exact height
|
||||||
|
|
@ -920,21 +922,21 @@ func TestChainTxReorgs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// overwrite the old chain
|
// overwrite the old chain
|
||||||
chain, _ = GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
|
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3)
|
pastAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
||||||
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
|
gen.AddTx(pastAdd) // This transaction needs to be injected during reorg
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
|
gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain
|
||||||
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
|
gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain
|
||||||
|
|
||||||
freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3)
|
freshAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
||||||
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
|
gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key3)
|
futureAdd, _ = types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key3)
|
||||||
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
|
gen.AddTx(futureAdd) // This transaction will be added after a full reorg
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -980,7 +982,8 @@ func TestLogReorgs(t *testing.T) {
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
// this code generates a log
|
// this code generates a log
|
||||||
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
|
||||||
|
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||||
)
|
)
|
||||||
genesis := WriteGenesisBlockForTesting(db,
|
genesis := WriteGenesisBlockForTesting(db,
|
||||||
GenesisAccount{addr1, big.NewInt(10000000000000)},
|
GenesisAccount{addr1, big.NewInt(10000000000000)},
|
||||||
|
|
@ -990,9 +993,9 @@ func TestLogReorgs(t *testing.T) {
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
||||||
|
|
||||||
subs := evmux.Subscribe(RemovedLogsEvent{})
|
subs := evmux.Subscribe(RemovedLogsEvent{})
|
||||||
chain, _ := GenerateChain(nil, genesis, db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(key1)
|
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code).SignECDSA(signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1003,7 +1006,7 @@ func TestLogReorgs(t *testing.T) {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
t.Fatalf("failed to insert chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
chain, _ = GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
|
chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert forked chain: %v", err)
|
t.Fatalf("failed to insert forked chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -1020,18 +1023,19 @@ func TestReorgSideEvent(t *testing.T) {
|
||||||
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
addr1 = crypto.PubkeyToAddress(key1.PublicKey)
|
||||||
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
|
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(10000000000000)})
|
||||||
|
signer = types.NewEIP155Signer(big.NewInt(1))
|
||||||
)
|
)
|
||||||
|
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
||||||
|
|
||||||
chain, _ := GenerateChain(nil, genesis, db, 3, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
t.Fatalf("failed to insert chain: %v", err)
|
t.Fatalf("failed to insert chain: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
replacementBlocks, _ := GenerateChain(nil, genesis, db, 4, func(i int, gen *BlockGen) {
|
replacementBlocks, _ := GenerateChain(params.TestChainConfig, genesis, db, 4, func(i int, gen *BlockGen) {
|
||||||
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(key1)
|
tx, err := types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil).SignECDSA(signer, key1)
|
||||||
if i == 2 {
|
if i == 2 {
|
||||||
gen.OffsetTime(-1)
|
gen.OffsetTime(-1)
|
||||||
}
|
}
|
||||||
|
|
@ -1101,7 +1105,7 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
blockchain, _ := NewBlockChain(db, testChainConfig(), FakePow{}, evmux)
|
||||||
|
|
||||||
chain, _ := GenerateChain(nil, genesis, db, 10, func(i int, gen *BlockGen) {})
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
for i, _ := range chain {
|
for i, _ := range chain {
|
||||||
go func(block *types.Block) {
|
go func(block *types.Block) {
|
||||||
|
|
@ -1128,3 +1132,102 @@ func TestCanonicalBlockRetrieval(t *testing.T) {
|
||||||
blockchain.InsertChain(types.Blocks{chain[i]})
|
blockchain.InsertChain(types.Blocks{chain[i]})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEIP155Transition(t *testing.T) {
|
||||||
|
// Configure and generate a sample block chain
|
||||||
|
var (
|
||||||
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
funds = big.NewInt(1000000000)
|
||||||
|
genesis = WriteGenesisBlockForTesting(db, GenesisAccount{address, funds})
|
||||||
|
config = ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
||||||
|
mux event.TypeMux
|
||||||
|
)
|
||||||
|
|
||||||
|
blockchain, _ := NewBlockChain(db, config, FakePow{}, &mux)
|
||||||
|
blocks, _ := GenerateChain(config, genesis, db, 4, func(i int, block *BlockGen) {
|
||||||
|
var (
|
||||||
|
tx *types.Transaction
|
||||||
|
err error
|
||||||
|
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
||||||
|
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
tx, err = basicTx(types.HomesteadSigner{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
case 2:
|
||||||
|
tx, err = basicTx(types.HomesteadSigner{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
|
||||||
|
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
case 3:
|
||||||
|
tx, err = basicTx(types.HomesteadSigner{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
|
||||||
|
tx, err = basicTx(types.NewEIP155Signer(config.ChainId))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if _, err := blockchain.InsertChain(blocks); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block := blockchain.GetBlockByNumber(1)
|
||||||
|
if block.Transactions()[0].Protected() {
|
||||||
|
t.Error("Expected block[0].txs[0] to not be replay protected")
|
||||||
|
}
|
||||||
|
|
||||||
|
block = blockchain.GetBlockByNumber(3)
|
||||||
|
if block.Transactions()[0].Protected() {
|
||||||
|
t.Error("Expected block[3].txs[0] to not be replay protected")
|
||||||
|
}
|
||||||
|
if !block.Transactions()[1].Protected() {
|
||||||
|
t.Error("Expected block[3].txs[1] to be replay protected")
|
||||||
|
}
|
||||||
|
if _, err := blockchain.InsertChain(blocks[4:]); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate an invalid chain id transaction
|
||||||
|
config = ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}
|
||||||
|
blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) {
|
||||||
|
var (
|
||||||
|
tx *types.Transaction
|
||||||
|
err error
|
||||||
|
basicTx = func(signer types.Signer) (*types.Transaction, error) {
|
||||||
|
return types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil).SignECDSA(signer, key)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
switch i {
|
||||||
|
case 0:
|
||||||
|
tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2)))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
block.AddTx(tx)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
_, err := blockchain.InsertChain(blocks)
|
||||||
|
if err != types.ErrInvalidChainId {
|
||||||
|
t.Error("expected error:", types.ErrInvalidChainId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,8 +35,8 @@ import (
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
|
// MakeChainConfig returns a new ChainConfig with the ethereum default chain settings.
|
||||||
func MakeChainConfig() *ChainConfig {
|
func MakeChainConfig() *params.ChainConfig {
|
||||||
return &ChainConfig{
|
return ¶ms.ChainConfig{
|
||||||
HomesteadBlock: big.NewInt(0),
|
HomesteadBlock: big.NewInt(0),
|
||||||
DAOForkBlock: nil,
|
DAOForkBlock: nil,
|
||||||
DAOForkSupport: true,
|
DAOForkSupport: true,
|
||||||
|
|
@ -73,6 +73,8 @@ type BlockGen struct {
|
||||||
txs []*types.Transaction
|
txs []*types.Transaction
|
||||||
receipts []*types.Receipt
|
receipts []*types.Receipt
|
||||||
uncles []*types.Header
|
uncles []*types.Header
|
||||||
|
|
||||||
|
config *params.ChainConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCoinbase sets the coinbase of the generated block.
|
// SetCoinbase sets the coinbase of the generated block.
|
||||||
|
|
@ -106,7 +108,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
|
||||||
b.SetCoinbase(common.Address{})
|
b.SetCoinbase(common.Address{})
|
||||||
}
|
}
|
||||||
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
|
b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs))
|
||||||
receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
receipt, _, _, err := ApplyTransaction(b.config, nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -178,10 +180,10 @@ func (b *BlockGen) OffsetTime(seconds int64) {
|
||||||
// Blocks created by GenerateChain do not contain valid proof of work
|
// Blocks created by GenerateChain do not contain valid proof of work
|
||||||
// values. Inserting them into BlockChain requires use of FakePow or
|
// values. Inserting them into BlockChain requires use of FakePow or
|
||||||
// a similar non-validating proof of work implementation.
|
// a similar non-validating proof of work implementation.
|
||||||
func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
|
func GenerateChain(config *params.ChainConfig, parent *types.Block, db ethdb.Database, n int, gen func(int, *BlockGen)) ([]*types.Block, []types.Receipts) {
|
||||||
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
blocks, receipts := make(types.Blocks, n), make([]types.Receipts, n)
|
||||||
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
genblock := func(i int, h *types.Header, statedb *state.StateDB) (*types.Block, types.Receipts) {
|
||||||
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb}
|
b := &BlockGen{parent: parent, i: i, chain: blocks, header: h, statedb: statedb, config: config}
|
||||||
|
|
||||||
// Mutate the state and block according to any hard-fork specs
|
// Mutate the state and block according to any hard-fork specs
|
||||||
if config == nil {
|
if config == nil {
|
||||||
|
|
@ -203,7 +205,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
|
||||||
gen(i, b)
|
gen(i, b)
|
||||||
}
|
}
|
||||||
AccumulateRewards(statedb, h, b.uncles)
|
AccumulateRewards(statedb, h, b.uncles)
|
||||||
root, err := statedb.Commit()
|
root, err := statedb.Commit(config.IsEIP158(h.Number))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("state write error: %v", err))
|
panic(fmt.Sprintf("state write error: %v", err))
|
||||||
}
|
}
|
||||||
|
|
@ -215,7 +217,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
header := makeHeader(parent, statedb)
|
header := makeHeader(config, parent, statedb)
|
||||||
block, receipt := genblock(i, header, statedb)
|
block, receipt := genblock(i, header, statedb)
|
||||||
blocks[i] = block
|
blocks[i] = block
|
||||||
receipts[i] = receipt
|
receipts[i] = receipt
|
||||||
|
|
@ -224,7 +226,7 @@ func GenerateChain(config *ChainConfig, parent *types.Block, db ethdb.Database,
|
||||||
return blocks, receipts
|
return blocks, receipts
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
|
func makeHeader(config *params.ChainConfig, parent *types.Block, state *state.StateDB) *types.Header {
|
||||||
var time *big.Int
|
var time *big.Int
|
||||||
if parent.Time() == nil {
|
if parent.Time() == nil {
|
||||||
time = big.NewInt(10)
|
time = big.NewInt(10)
|
||||||
|
|
@ -232,7 +234,7 @@ func makeHeader(parent *types.Block, state *state.StateDB) *types.Header {
|
||||||
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
time = new(big.Int).Add(parent.Time(), big.NewInt(10)) // block time is fixed at 10 seconds
|
||||||
}
|
}
|
||||||
return &types.Header{
|
return &types.Header{
|
||||||
Root: state.IntermediateRoot(),
|
Root: state.IntermediateRoot(config.IsEIP158(parent.Number())),
|
||||||
ParentHash: parent.Hash(),
|
ParentHash: parent.Hash(),
|
||||||
Coinbase: parent.Coinbase(),
|
Coinbase: parent.Coinbase(),
|
||||||
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
Difficulty: CalcDifficulty(MakeChainConfig(), time.Uint64(), new(big.Int).Sub(time, big.NewInt(10)).Uint64(), parent.Number(), parent.Difficulty()),
|
||||||
|
|
@ -283,7 +285,7 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
|
||||||
|
|
||||||
// makeBlockChain creates a deterministic chain of blocks rooted at parent.
|
// makeBlockChain creates a deterministic chain of blocks rooted at parent.
|
||||||
func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
|
func makeBlockChain(parent *types.Block, n int, db ethdb.Database, seed int) []*types.Block {
|
||||||
blocks, _ := GenerateChain(nil, parent, db, n, func(i int, b *BlockGen) {
|
blocks, _ := GenerateChain(params.TestChainConfig, parent, db, n, func(i int, b *BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
||||||
})
|
})
|
||||||
return blocks
|
return blocks
|
||||||
|
|
|
||||||
|
|
@ -39,25 +39,29 @@ func ExampleGenerateChain() {
|
||||||
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
addr2 = crypto.PubkeyToAddress(key2.PublicKey)
|
||||||
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
addr3 = crypto.PubkeyToAddress(key3.PublicKey)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
|
signer = types.HomesteadSigner{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
chainConfig := ¶ms.ChainConfig{
|
||||||
|
HomesteadBlock: new(big.Int),
|
||||||
|
}
|
||||||
// Ensure that key1 has some funds in the genesis block.
|
// Ensure that key1 has some funds in the genesis block.
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
|
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr1, big.NewInt(1000000)})
|
||||||
|
|
||||||
// This call generates a chain of 5 blocks. The function runs for
|
// This call generates a chain of 5 blocks. The function runs for
|
||||||
// each block and adds different features to gen based on the
|
// each block and adds different features to gen based on the
|
||||||
// block index.
|
// block index.
|
||||||
chain, _ := GenerateChain(nil, genesis, db, 5, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(chainConfig, genesis, db, 5, func(i int, gen *BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, addr1 sends addr2 some ether.
|
// In block 1, addr1 sends addr2 some ether.
|
||||||
tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(key1)
|
tx, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
||||||
gen.AddTx(tx)
|
gen.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, addr1 sends some more ether to addr2.
|
// In block 2, addr1 sends some more ether to addr2.
|
||||||
// addr2 passes it on to addr3.
|
// addr2 passes it on to addr3.
|
||||||
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key1)
|
tx1, _ := types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key1)
|
||||||
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(key2)
|
tx2, _ := types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, key2)
|
||||||
gen.AddTx(tx1)
|
gen.AddTx(tx1)
|
||||||
gen.AddTx(tx2)
|
gen.AddTx(tx2)
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -77,7 +81,7 @@ func ExampleGenerateChain() {
|
||||||
|
|
||||||
// Import the chain. This runs all block validation rules.
|
// Import the chain. This runs all block validation rules.
|
||||||
evmux := &event.TypeMux{}
|
evmux := &event.TypeMux{}
|
||||||
blockchain, _ := NewBlockChain(db, MakeChainConfig(), FakePow{}, evmux)
|
blockchain, _ := NewBlockChain(db, chainConfig, FakePow{}, evmux)
|
||||||
if i, err := blockchain.InsertChain(chain); err != nil {
|
if i, err := blockchain.InsertChain(chain); err != nil {
|
||||||
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -60,7 +61,7 @@ func TestPowVerification(t *testing.T) {
|
||||||
var (
|
var (
|
||||||
testdb, _ = ethdb.NewMemDatabase()
|
testdb, _ = ethdb.NewMemDatabase()
|
||||||
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
||||||
blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
|
blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
|
||||||
)
|
)
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -115,7 +116,7 @@ func testPowConcurrentVerification(t *testing.T, threads int) {
|
||||||
var (
|
var (
|
||||||
testdb, _ = ethdb.NewMemDatabase()
|
testdb, _ = ethdb.NewMemDatabase()
|
||||||
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
||||||
blocks, _ = GenerateChain(nil, genesis, testdb, 8, nil)
|
blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 8, nil)
|
||||||
)
|
)
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
@ -186,7 +187,7 @@ func testPowConcurrentAbortion(t *testing.T, threads int) {
|
||||||
var (
|
var (
|
||||||
testdb, _ = ethdb.NewMemDatabase()
|
testdb, _ = ethdb.NewMemDatabase()
|
||||||
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
genesis = GenesisBlockForTesting(testdb, common.Address{}, new(big.Int))
|
||||||
blocks, _ = GenerateChain(nil, genesis, testdb, 1024, nil)
|
blocks, _ = GenerateChain(params.TestChainConfig, genesis, testdb, 1024, nil)
|
||||||
)
|
)
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
for i, block := range blocks {
|
for i, block := range blocks {
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
// Copyright 2016 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
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"math/big"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
|
|
||||||
|
|
||||||
// ChainConfig is the core config which determines the blockchain settings.
|
|
||||||
//
|
|
||||||
// ChainConfig is stored in the database on a per block basis. This means
|
|
||||||
// that any network, identified by its genesis block, can have its own
|
|
||||||
// set of configuration options.
|
|
||||||
type ChainConfig struct {
|
|
||||||
HomesteadBlock *big.Int `json:"homesteadBlock"` // Homestead switch block (nil = no fork, 0 = already homestead)
|
|
||||||
DAOForkBlock *big.Int `json:"daoForkBlock"` // TheDAO hard-fork switch block (nil = no fork)
|
|
||||||
DAOForkSupport bool `json:"daoForkSupport"` // Whether the nodes supports or opposes the DAO hard-fork
|
|
||||||
|
|
||||||
HomesteadGasRepriceBlock *big.Int `json:"homesteadGasRepriceBlock"` // Homestead gas reprice switch block (nil = no fork)
|
|
||||||
HomesteadGasRepriceHash common.Hash `json:"homesteadGasRepriceHash"` // Homestead gas reprice switch block hash (fast sync aid)
|
|
||||||
|
|
||||||
VmConfig vm.Config `json:"-"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsHomestead returns whether num is either equal to the homestead block or greater.
|
|
||||||
func (c *ChainConfig) IsHomestead(num *big.Int) bool {
|
|
||||||
if c.HomesteadBlock == nil || num == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return num.Cmp(c.HomesteadBlock) >= 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice).
|
|
||||||
//
|
|
||||||
// The returned GasTable's fields shouldn't, under any circumstances, be changed.
|
|
||||||
func (c *ChainConfig) GasTable(num *big.Int) params.GasTable {
|
|
||||||
if c.HomesteadGasRepriceBlock == nil || num == nil || num.Cmp(c.HomesteadGasRepriceBlock) < 0 {
|
|
||||||
return params.GasTableHomestead
|
|
||||||
}
|
|
||||||
|
|
||||||
return params.GasTableHomesteadGasRepriceFork
|
|
||||||
}
|
|
||||||
|
|
@ -33,7 +33,7 @@ import (
|
||||||
// with the fork specific extra-data set
|
// with the fork specific extra-data set
|
||||||
// b) if the node is pro-fork, require blocks in the specific range to have the
|
// b) if the node is pro-fork, require blocks in the specific range to have the
|
||||||
// unique extra-data set.
|
// unique extra-data set.
|
||||||
func ValidateDAOHeaderExtraData(config *ChainConfig, header *types.Header) error {
|
func ValidateDAOHeaderExtraData(config *params.ChainConfig, header *types.Header) error {
|
||||||
// Short circuit validation if the node doesn't care about the DAO fork
|
// Short circuit validation if the node doesn't care about the DAO fork
|
||||||
if config.DAOForkBlock == nil {
|
if config.DAOForkBlock == nil {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -33,17 +33,17 @@ func TestDAOForkRangeExtradata(t *testing.T) {
|
||||||
// Generate a common prefix for both pro-forkers and non-forkers
|
// Generate a common prefix for both pro-forkers and non-forkers
|
||||||
db, _ := ethdb.NewMemDatabase()
|
db, _ := ethdb.NewMemDatabase()
|
||||||
genesis := WriteGenesisBlockForTesting(db)
|
genesis := WriteGenesisBlockForTesting(db)
|
||||||
prefix, _ := GenerateChain(nil, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
prefix, _ := GenerateChain(params.TestChainConfig, genesis, db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {})
|
||||||
|
|
||||||
// Create the concurrent, conflicting two nodes
|
// Create the concurrent, conflicting two nodes
|
||||||
proDb, _ := ethdb.NewMemDatabase()
|
proDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(proDb)
|
WriteGenesisBlockForTesting(proDb)
|
||||||
proConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
proConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: true}
|
||||||
proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux))
|
proBc, _ := NewBlockChain(proDb, proConf, new(FakePow), new(event.TypeMux))
|
||||||
|
|
||||||
conDb, _ := ethdb.NewMemDatabase()
|
conDb, _ := ethdb.NewMemDatabase()
|
||||||
WriteGenesisBlockForTesting(conDb)
|
WriteGenesisBlockForTesting(conDb)
|
||||||
conConf := &ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
conConf := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0), DAOForkBlock: forkBlock, DAOForkSupport: false}
|
||||||
conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux))
|
conBc, _ := NewBlockChain(conDb, conConf, new(FakePow), new(event.TypeMux))
|
||||||
|
|
||||||
if _, err := proBc.InsertChain(prefix); err != nil {
|
if _, err := proBc.InsertChain(prefix); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -28,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -59,6 +61,8 @@ var (
|
||||||
oldBlockNumPrefix = []byte("block-num-")
|
oldBlockNumPrefix = []byte("block-num-")
|
||||||
oldBlockReceiptsPrefix = []byte("receipts-block-")
|
oldBlockReceiptsPrefix = []byte("receipts-block-")
|
||||||
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
|
oldBlockHashPrefix = []byte("block-hash-") // [deprecated by the header/block split, remove eventually]
|
||||||
|
|
||||||
|
ChainConfigNotFoundErr = errors.New("ChainConfig not found") // general config not found error
|
||||||
)
|
)
|
||||||
|
|
||||||
// encodeBlockNumber encodes a block number as big endian uint64
|
// encodeBlockNumber encodes a block number as big endian uint64
|
||||||
|
|
@ -600,7 +604,7 @@ func WriteBlockChainVersion(db ethdb.Database, vsn int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteChainConfig writes the chain config settings to the database.
|
// WriteChainConfig writes the chain config settings to the database.
|
||||||
func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) error {
|
func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *params.ChainConfig) error {
|
||||||
// short circuit and ignore if nil config. GetChainConfig
|
// short circuit and ignore if nil config. GetChainConfig
|
||||||
// will return a default.
|
// will return a default.
|
||||||
if cfg == nil {
|
if cfg == nil {
|
||||||
|
|
@ -616,13 +620,13 @@ func WriteChainConfig(db ethdb.Database, hash common.Hash, cfg *ChainConfig) err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChainConfig will fetch the network settings based on the given hash.
|
// GetChainConfig will fetch the network settings based on the given hash.
|
||||||
func GetChainConfig(db ethdb.Database, hash common.Hash) (*ChainConfig, error) {
|
func GetChainConfig(db ethdb.Database, hash common.Hash) (*params.ChainConfig, error) {
|
||||||
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
|
jsonChainConfig, _ := db.Get(append(configPrefix, hash[:]...))
|
||||||
if len(jsonChainConfig) == 0 {
|
if len(jsonChainConfig) == 0 {
|
||||||
return nil, ChainConfigNotFoundErr
|
return nil, ChainConfigNotFoundErr
|
||||||
}
|
}
|
||||||
|
|
||||||
var config ChainConfig
|
var config params.ChainConfig
|
||||||
if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
|
if err := json.Unmarshal(jsonChainConfig, &config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -75,7 +76,7 @@ func TestCalcDifficulty(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
config := &ChainConfig{HomesteadBlock: big.NewInt(1150000)}
|
config := ¶ms.ChainConfig{HomesteadBlock: big.NewInt(1150000)}
|
||||||
for name, test := range tests {
|
for name, test := range tests {
|
||||||
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
number := new(big.Int).Sub(test.CurrentBlocknumber, big.NewInt(1))
|
||||||
diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
|
diff := CalcDifficulty(config, test.CurrentTimestamp, test.ParentTimestamp, number, test.ParentDifficulty)
|
||||||
|
|
@ -562,7 +563,7 @@ func TestMipmapChain(t *testing.T) {
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
|
genesis := WriteGenesisBlockForTesting(db, GenesisAccount{addr, big.NewInt(1000000)})
|
||||||
chain, receipts := GenerateChain(nil, genesis, db, 1010, func(i int, gen *BlockGen) {
|
chain, receipts := GenerateChain(params.TestChainConfig, genesis, db, 1010, func(i int, gen *BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
||||||
|
|
@ -27,62 +27,17 @@ import (
|
||||||
|
|
||||||
// Call executes within the given contract
|
// Call executes within the given contract
|
||||||
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
func Call(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
||||||
ret, _, err = exec(env, caller, &addr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// CallCode executes the given address' code as the given contract address
|
|
||||||
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
|
||||||
callerAddr := caller.Address()
|
|
||||||
ret, _, err = exec(env, caller, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, value)
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
|
|
||||||
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
|
|
||||||
callerAddr := caller.Address()
|
|
||||||
originAddr := env.Origin()
|
|
||||||
callerValue := caller.Value()
|
|
||||||
ret, _, err = execDelegateCall(env, caller, &originAddr, &callerAddr, &addr, env.Db().GetCodeHash(addr), input, env.Db().GetCode(addr), gas, gasPrice, callerValue)
|
|
||||||
return ret, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create creates a new contract with the given code
|
|
||||||
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
|
|
||||||
ret, address, err = exec(env, caller, nil, nil, crypto.Keccak256Hash(code), nil, code, gas, gasPrice, value)
|
|
||||||
// Here we get an error if we run into maximum stack depth,
|
|
||||||
// See: https://github.com/ethereum/yellowpaper/pull/131
|
|
||||||
// and YP definitions for CREATE instruction
|
|
||||||
if err != nil {
|
|
||||||
return nil, address, err
|
|
||||||
}
|
|
||||||
return ret, address, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
|
|
||||||
evm := env.Vm()
|
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas, gasPrice)
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
return nil, common.Address{}, vm.DepthError
|
return nil, vm.DepthError
|
||||||
}
|
}
|
||||||
|
|
||||||
if !env.CanTransfer(caller.Address(), value) {
|
if !env.CanTransfer(caller.Address(), value) {
|
||||||
caller.ReturnGas(gas, gasPrice)
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
||||||
}
|
|
||||||
|
|
||||||
var createAccount bool
|
|
||||||
if address == nil {
|
|
||||||
// Create a new account on the state
|
|
||||||
nonce := env.Db().GetNonce(caller.Address())
|
|
||||||
env.Db().SetNonce(caller.Address(), nonce+1)
|
|
||||||
addr = crypto.CreateAddress(caller.Address(), nonce)
|
|
||||||
address = &addr
|
|
||||||
createAccount = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshotPreTransfer := env.SnapshotDatabase()
|
snapshotPreTransfer := env.SnapshotDatabase()
|
||||||
|
|
@ -90,14 +45,15 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
|
||||||
from = env.Db().GetAccount(caller.Address())
|
from = env.Db().GetAccount(caller.Address())
|
||||||
to vm.Account
|
to vm.Account
|
||||||
)
|
)
|
||||||
if createAccount {
|
if !env.Db().Exist(addr) {
|
||||||
to = env.Db().CreateAccount(*address)
|
if vm.Precompiled[addr.Str()] == nil && env.ChainConfig().IsEIP158(env.BlockNumber()) && value.BitLen() == 0 {
|
||||||
} else {
|
caller.ReturnGas(gas, gasPrice)
|
||||||
if !env.Db().Exist(*address) {
|
return nil, nil
|
||||||
to = env.Db().CreateAccount(*address)
|
|
||||||
} else {
|
|
||||||
to = env.Db().GetAccount(*address)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
to = env.Db().CreateAccount(addr)
|
||||||
|
} else {
|
||||||
|
to = env.Db().GetAccount(addr)
|
||||||
}
|
}
|
||||||
env.Transfer(from, to, value)
|
env.Transfer(from, to, value)
|
||||||
|
|
||||||
|
|
@ -105,19 +61,106 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
|
||||||
// EVM. The contract is a scoped environment for this execution context
|
// EVM. The contract is a scoped environment for this execution context
|
||||||
// only.
|
// only.
|
||||||
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
||||||
contract.SetCallCode(codeAddr, codeHash, code)
|
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err = evm.Run(contract, input)
|
ret, err = env.Vm().Run(contract, input)
|
||||||
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
env.RevertToSnapshot(snapshotPreTransfer)
|
||||||
|
}
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallCode executes the given address' code as the given contract address
|
||||||
|
func CallCode(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice, value *big.Int) (ret []byte, err error) {
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
|
return nil, vm.DepthError
|
||||||
|
}
|
||||||
|
if !env.CanTransfer(caller.Address(), value) {
|
||||||
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
|
return nil, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
snapshotPreTransfer = env.SnapshotDatabase()
|
||||||
|
to = env.Db().GetAccount(caller.Address())
|
||||||
|
)
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// EVM. The contract is a scoped environment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
||||||
|
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = env.Vm().Run(contract, input)
|
||||||
|
if err != nil {
|
||||||
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
|
env.RevertToSnapshot(snapshotPreTransfer)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create creates a new contract with the given code
|
||||||
|
func Create(env vm.Environment, caller vm.ContractRef, code []byte, gas, gasPrice, value *big.Int) (ret []byte, address common.Address, err error) {
|
||||||
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
|
// limit.
|
||||||
|
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||||
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
|
return nil, common.Address{}, vm.DepthError
|
||||||
|
}
|
||||||
|
if !env.CanTransfer(caller.Address(), value) {
|
||||||
|
caller.ReturnGas(gas, gasPrice)
|
||||||
|
|
||||||
|
return nil, common.Address{}, ValueTransferErr("insufficient funds to transfer value. Req %v, has %v", value, env.Db().GetBalance(caller.Address()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new account on the state
|
||||||
|
nonce := env.Db().GetNonce(caller.Address())
|
||||||
|
env.Db().SetNonce(caller.Address(), nonce+1)
|
||||||
|
|
||||||
|
snapshotPreTransfer := env.SnapshotDatabase()
|
||||||
|
var (
|
||||||
|
addr = crypto.CreateAddress(caller.Address(), nonce)
|
||||||
|
from = env.Db().GetAccount(caller.Address())
|
||||||
|
to = env.Db().CreateAccount(addr)
|
||||||
|
)
|
||||||
|
if env.ChainConfig().IsEIP158(env.BlockNumber()) {
|
||||||
|
env.Db().SetNonce(addr, 1)
|
||||||
|
}
|
||||||
|
env.Transfer(from, to, value)
|
||||||
|
|
||||||
|
// initialise a new contract and set the code that is to be used by the
|
||||||
|
// EVM. The contract is a scoped environment for this execution context
|
||||||
|
// only.
|
||||||
|
contract := vm.NewContract(caller, to, value, gas, gasPrice)
|
||||||
|
contract.SetCallCode(&addr, crypto.Keccak256Hash(code), code)
|
||||||
|
defer contract.Finalise()
|
||||||
|
|
||||||
|
ret, err = env.Vm().Run(contract, nil)
|
||||||
|
// check whether the max code size has been exceeded
|
||||||
|
maxCodeSizeExceeded := len(ret) > params.MaxCodeSize
|
||||||
// if the contract creation ran successfully and no errors were returned
|
// if the contract creation ran successfully and no errors were returned
|
||||||
// calculate the gas required to store the code. If the code could not
|
// calculate the gas required to store the code. If the code could not
|
||||||
// be stored due to not enough gas set an error and let it be handled
|
// be stored due to not enough gas set an error and let it be handled
|
||||||
// by the error checking condition below.
|
// by the error checking condition below.
|
||||||
if err == nil && createAccount {
|
if err == nil && !maxCodeSizeExceeded {
|
||||||
dataGas := big.NewInt(int64(len(ret)))
|
dataGas := big.NewInt(int64(len(ret)))
|
||||||
dataGas.Mul(dataGas, params.CreateDataGas)
|
dataGas.Mul(dataGas, params.CreateDataGas)
|
||||||
if contract.UseGas(dataGas) {
|
if contract.UseGas(dataGas) {
|
||||||
env.Db().SetCode(*address, ret)
|
env.Db().SetCode(addr, ret)
|
||||||
} else {
|
} else {
|
||||||
err = vm.CodeStoreOutOfGasError
|
err = vm.CodeStoreOutOfGasError
|
||||||
}
|
}
|
||||||
|
|
@ -126,46 +169,45 @@ func exec(env vm.Environment, caller vm.ContractRef, address, codeAddr *common.A
|
||||||
// When an error was returned by the EVM or when setting the creation code
|
// When an error was returned by the EVM or when setting the creation code
|
||||||
// above we revert to the snapshot and consume any gas remaining. Additionally
|
// above we revert to the snapshot and consume any gas remaining. Additionally
|
||||||
// when we're in homestead this also counts for code storage gas errors.
|
// when we're in homestead this also counts for code storage gas errors.
|
||||||
if err != nil && (env.RuleSet().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError) {
|
if maxCodeSizeExceeded ||
|
||||||
|
(err != nil && (env.ChainConfig().IsHomestead(env.BlockNumber()) || err != vm.CodeStoreOutOfGasError)) {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
env.RevertToSnapshot(snapshotPreTransfer)
|
env.RevertToSnapshot(snapshotPreTransfer)
|
||||||
|
|
||||||
|
// Nothing should be returned when an error is thrown.
|
||||||
|
return nil, addr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, addr, err
|
return ret, addr, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func execDelegateCall(env vm.Environment, caller vm.ContractRef, originAddr, toAddr, codeAddr *common.Address, codeHash common.Hash, input, code []byte, gas, gasPrice, value *big.Int) (ret []byte, addr common.Address, err error) {
|
// DelegateCall is equivalent to CallCode except that sender and value propagates from parent scope to child scope
|
||||||
evm := env.Vm()
|
func DelegateCall(env vm.Environment, caller vm.ContractRef, addr common.Address, input []byte, gas, gasPrice *big.Int) (ret []byte, err error) {
|
||||||
// Depth check execution. Fail if we're trying to execute above the
|
// Depth check execution. Fail if we're trying to execute above the
|
||||||
// limit.
|
// limit.
|
||||||
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
if env.Depth() > int(params.CallCreateDepth.Int64()) {
|
||||||
caller.ReturnGas(gas, gasPrice)
|
caller.ReturnGas(gas, gasPrice)
|
||||||
return nil, common.Address{}, vm.DepthError
|
return nil, vm.DepthError
|
||||||
}
|
}
|
||||||
|
|
||||||
snapshot := env.SnapshotDatabase()
|
var (
|
||||||
|
snapshot = env.SnapshotDatabase()
|
||||||
var to vm.Account
|
to = env.Db().GetAccount(caller.Address())
|
||||||
if !env.Db().Exist(*toAddr) {
|
)
|
||||||
to = env.Db().CreateAccount(*toAddr)
|
|
||||||
} else {
|
|
||||||
to = env.Db().GetAccount(*toAddr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iinitialise a new contract and make initialise the delegate values
|
// Iinitialise a new contract and make initialise the delegate values
|
||||||
contract := vm.NewContract(caller, to, value, gas, gasPrice).AsDelegate()
|
contract := vm.NewContract(caller, to, caller.Value(), gas, gasPrice).AsDelegate()
|
||||||
contract.SetCallCode(codeAddr, codeHash, code)
|
contract.SetCallCode(&addr, env.Db().GetCodeHash(addr), env.Db().GetCode(addr))
|
||||||
defer contract.Finalise()
|
defer contract.Finalise()
|
||||||
|
|
||||||
ret, err = evm.Run(contract, input)
|
ret, err = env.Vm().Run(contract, input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
contract.UseGas(contract.Gas)
|
contract.UseGas(contract.Gas)
|
||||||
|
|
||||||
env.RevertToSnapshot(snapshot)
|
env.RevertToSnapshot(snapshot)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret, addr, err
|
return ret, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic transfer method
|
// generic transfer method
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
}
|
}
|
||||||
|
|
||||||
var genesis struct {
|
var genesis struct {
|
||||||
ChainConfig *ChainConfig `json:"config"`
|
ChainConfig *params.ChainConfig `json:"config"`
|
||||||
Nonce string
|
Nonce string
|
||||||
Timestamp string
|
Timestamp string
|
||||||
ParentHash string
|
ParentHash string
|
||||||
|
|
@ -73,7 +73,7 @@ func WriteGenesisBlock(chainDb ethdb.Database, reader io.Reader) (*types.Block,
|
||||||
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
|
statedb.SetState(address, common.HexToHash(key), common.HexToHash(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root, stateBatch := statedb.CommitBatch()
|
root, stateBatch := statedb.CommitBatch(false)
|
||||||
|
|
||||||
difficulty := common.String2Big(genesis.Difficulty)
|
difficulty := common.String2Big(genesis.Difficulty)
|
||||||
block := types.NewBlock(&types.Header{
|
block := types.NewBlock(&types.Header{
|
||||||
|
|
@ -128,7 +128,7 @@ func GenesisBlockForTesting(db ethdb.Database, addr common.Address, balance *big
|
||||||
statedb, _ := state.New(common.Hash{}, db)
|
statedb, _ := state.New(common.Hash{}, db)
|
||||||
obj := statedb.GetOrNewStateObject(addr)
|
obj := statedb.GetOrNewStateObject(addr)
|
||||||
obj.SetBalance(balance)
|
obj.SetBalance(balance)
|
||||||
root, err := statedb.Commit()
|
root, err := statedb.Commit(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(fmt.Sprintf("cannot write state: %v", err))
|
panic(fmt.Sprintf("cannot write state: %v", err))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
)
|
)
|
||||||
|
|
@ -48,7 +49,7 @@ const (
|
||||||
// It is not thread safe either, the encapsulating chain structures should do
|
// It is not thread safe either, the encapsulating chain structures should do
|
||||||
// the necessary mutex locking/unlocking.
|
// the necessary mutex locking/unlocking.
|
||||||
type HeaderChain struct {
|
type HeaderChain struct {
|
||||||
config *ChainConfig
|
config *params.ChainConfig
|
||||||
|
|
||||||
chainDb ethdb.Database
|
chainDb ethdb.Database
|
||||||
genesisHeader *types.Header
|
genesisHeader *types.Header
|
||||||
|
|
@ -73,7 +74,7 @@ type getHeaderValidatorFn func() HeaderValidator
|
||||||
// getValidator should return the parent's validator
|
// getValidator should return the parent's validator
|
||||||
// procInterrupt points to the parent's interrupt semaphore
|
// procInterrupt points to the parent's interrupt semaphore
|
||||||
// wg points to the parent's shutdown wait group
|
// wg points to the parent's shutdown wait group
|
||||||
func NewHeaderChain(chainDb ethdb.Database, config *ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
|
func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, getValidator getHeaderValidatorFn, procInterrupt func() bool) (*HeaderChain, error) {
|
||||||
headerCache, _ := lru.New(headerCacheLimit)
|
headerCache, _ := lru.New(headerCacheLimit)
|
||||||
tdCache, _ := lru.New(tdCacheLimit)
|
tdCache, _ := lru.New(tdCacheLimit)
|
||||||
numberCache, _ := lru.New(numberCacheLimit)
|
numberCache, _ := lru.New(numberCacheLimit)
|
||||||
|
|
@ -490,13 +491,13 @@ func (hc *HeaderChain) SetGenesis(head *types.Header) {
|
||||||
//
|
//
|
||||||
// headerValidator implements HeaderValidator.
|
// headerValidator implements HeaderValidator.
|
||||||
type headerValidator struct {
|
type headerValidator struct {
|
||||||
config *ChainConfig
|
config *params.ChainConfig
|
||||||
hc *HeaderChain // Canonical header chain
|
hc *HeaderChain // Canonical header chain
|
||||||
Pow pow.PoW // Proof of work used for validating
|
Pow pow.PoW // Proof of work used for validating
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBlockValidator returns a new block validator which is safe for re-use
|
// NewBlockValidator returns a new block validator which is safe for re-use
|
||||||
func NewHeaderValidator(config *ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
|
func NewHeaderValidator(config *params.ChainConfig, chain *HeaderChain, pow pow.PoW) HeaderValidator {
|
||||||
return &headerValidator{
|
return &headerValidator{
|
||||||
config: config,
|
config: config,
|
||||||
Pow: pow,
|
Pow: pow,
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,11 @@ type StateObject struct {
|
||||||
onDirty func(addr common.Address) // Callback method to mark a state object newly dirty
|
onDirty func(addr common.Address) // Callback method to mark a state object newly dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// empty returns whether the account is considered empty.
|
||||||
|
func (s *StateObject) empty() bool {
|
||||||
|
return s.data.Nonce == 0 && s.data.Balance.BitLen() == 0 && bytes.Equal(s.data.CodeHash, emptyCodeHash)
|
||||||
|
}
|
||||||
|
|
||||||
// Account is the Ethereum consensus representation of accounts.
|
// Account is the Ethereum consensus representation of accounts.
|
||||||
// These objects are stored in the main account trie.
|
// These objects are stored in the main account trie.
|
||||||
type Account struct {
|
type Account struct {
|
||||||
|
|
@ -221,8 +226,12 @@ func (self *StateObject) CommitTrie(db trie.Database, dbw trie.DatabaseWriter) e
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddBalance removes amount from c's balance.
|
||||||
|
// It is used to add funds to the destination account of a transfer.
|
||||||
func (c *StateObject) AddBalance(amount *big.Int) {
|
func (c *StateObject) AddBalance(amount *big.Int) {
|
||||||
if amount.Cmp(common.Big0) == 0 {
|
// EIP158: We must check emptiness for the objects such that the account
|
||||||
|
// clearing (0,0,0 objects) can take effect.
|
||||||
|
if amount.Cmp(common.Big0) == 0 && !c.empty() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
c.SetBalance(new(big.Int).Add(c.Balance(), amount))
|
c.SetBalance(new(big.Int).Add(c.Balance(), amount))
|
||||||
|
|
@ -232,6 +241,8 @@ func (c *StateObject) AddBalance(amount *big.Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SubBalance removes amount from c's balance.
|
||||||
|
// It is used to remove funds from the origin account of a transfer.
|
||||||
func (c *StateObject) SubBalance(amount *big.Int) {
|
func (c *StateObject) SubBalance(amount *big.Int) {
|
||||||
if amount.Cmp(common.Big0) == 0 {
|
if amount.Cmp(common.Big0) == 0 {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ func (s *StateSuite) TestDump(c *checker.C) {
|
||||||
// write some of them to the trie
|
// write some of them to the trie
|
||||||
s.state.updateStateObject(obj1)
|
s.state.updateStateObject(obj1)
|
||||||
s.state.updateStateObject(obj2)
|
s.state.updateStateObject(obj2)
|
||||||
s.state.Commit()
|
s.state.Commit(false)
|
||||||
|
|
||||||
// check that dump contains the state objects that are in trie
|
// check that dump contains the state objects that are in trie
|
||||||
got := string(s.state.Dump())
|
got := string(s.state.Dump())
|
||||||
|
|
@ -100,7 +100,7 @@ func TestNull(t *testing.T) {
|
||||||
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
//value := common.FromHex("0x823140710bf13990e4500136726d8b55")
|
||||||
var value common.Hash
|
var value common.Hash
|
||||||
state.SetState(address, common.Hash{}, value)
|
state.SetState(address, common.Hash{}, value)
|
||||||
state.Commit()
|
state.Commit(false)
|
||||||
value = state.GetState(address, common.Hash{})
|
value = state.GetState(address, common.Hash{})
|
||||||
if !common.EmptyHash(value) {
|
if !common.EmptyHash(value) {
|
||||||
t.Errorf("expected empty hash. got %x", value)
|
t.Errorf("expected empty hash. got %x", value)
|
||||||
|
|
@ -160,7 +160,7 @@ func TestSnapshot2(t *testing.T) {
|
||||||
so0.deleted = false
|
so0.deleted = false
|
||||||
state.setStateObject(so0)
|
state.setStateObject(so0)
|
||||||
|
|
||||||
root, _ := state.Commit()
|
root, _ := state.Commit(false)
|
||||||
state.Reset(root)
|
state.Reset(root)
|
||||||
|
|
||||||
// and one with deleted == true
|
// and one with deleted == true
|
||||||
|
|
|
||||||
|
|
@ -213,6 +213,13 @@ func (self *StateDB) Exist(addr common.Address) bool {
|
||||||
return self.GetStateObject(addr) != nil
|
return self.GetStateObject(addr) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Empty returns whether the state object is either non-existant
|
||||||
|
// or empty according to the EIP161 specification (balance = nonce = code = 0)
|
||||||
|
func (self *StateDB) Empty(addr common.Address) bool {
|
||||||
|
so := self.GetStateObject(addr)
|
||||||
|
return so == nil || so.empty()
|
||||||
|
}
|
||||||
|
|
||||||
func (self *StateDB) GetAccount(addr common.Address) vm.Account {
|
func (self *StateDB) GetAccount(addr common.Address) vm.Account {
|
||||||
return self.GetStateObject(addr)
|
return self.GetStateObject(addr)
|
||||||
}
|
}
|
||||||
|
|
@ -516,10 +523,10 @@ func (self *StateDB) GetRefund() *big.Int {
|
||||||
// IntermediateRoot computes the current root hash of the state trie.
|
// IntermediateRoot computes the current root hash of the state trie.
|
||||||
// It is called in between transactions to get the root hash that
|
// It is called in between transactions to get the root hash that
|
||||||
// goes into transaction receipts.
|
// goes into transaction receipts.
|
||||||
func (s *StateDB) IntermediateRoot() common.Hash {
|
func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
for addr, _ := range s.stateObjectsDirty {
|
for addr, _ := range s.stateObjectsDirty {
|
||||||
stateObject := s.stateObjects[addr]
|
stateObject := s.stateObjects[addr]
|
||||||
if stateObject.suicided {
|
if stateObject.suicided || (deleteEmptyObjects && stateObject.empty()) {
|
||||||
s.deleteStateObject(stateObject)
|
s.deleteStateObject(stateObject)
|
||||||
} else {
|
} else {
|
||||||
stateObject.updateRoot(s.db)
|
stateObject.updateRoot(s.db)
|
||||||
|
|
@ -553,17 +560,17 @@ func (s *StateDB) DeleteSuicides() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit commits all state changes to the database.
|
// Commit commits all state changes to the database.
|
||||||
func (s *StateDB) Commit() (root common.Hash, err error) {
|
func (s *StateDB) Commit(deleteEmptyObjects bool) (root common.Hash, err error) {
|
||||||
root, batch := s.CommitBatch()
|
root, batch := s.CommitBatch(deleteEmptyObjects)
|
||||||
return root, batch.Write()
|
return root, batch.Write()
|
||||||
}
|
}
|
||||||
|
|
||||||
// CommitBatch commits all state changes to a write batch but does not
|
// CommitBatch commits all state changes to a write batch but does not
|
||||||
// execute the batch. It is used to validate state changes against
|
// execute the batch. It is used to validate state changes against
|
||||||
// the root hash stored in a block.
|
// the root hash stored in a block.
|
||||||
func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
|
func (s *StateDB) CommitBatch(deleteEmptyObjects bool) (root common.Hash, batch ethdb.Batch) {
|
||||||
batch = s.db.NewBatch()
|
batch = s.db.NewBatch()
|
||||||
root, _ = s.commit(batch)
|
root, _ = s.commit(batch, deleteEmptyObjects)
|
||||||
|
|
||||||
glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads())
|
glog.V(logger.Debug).Infof("Trie cache stats: %d misses, %d unloads", trie.CacheMisses(), trie.CacheUnloads())
|
||||||
return root, batch
|
return root, batch
|
||||||
|
|
@ -575,16 +582,18 @@ func (s *StateDB) clearJournalAndRefund() {
|
||||||
s.refund = new(big.Int)
|
s.refund = new(big.Int)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) commit(dbw trie.DatabaseWriter) (root common.Hash, err error) {
|
func (s *StateDB) commit(dbw trie.DatabaseWriter, deleteEmptyObjects bool) (root common.Hash, err error) {
|
||||||
defer s.clearJournalAndRefund()
|
defer s.clearJournalAndRefund()
|
||||||
|
|
||||||
// Commit objects to the trie.
|
// Commit objects to the trie.
|
||||||
for addr, stateObject := range s.stateObjects {
|
for addr, stateObject := range s.stateObjects {
|
||||||
if stateObject.suicided {
|
_, isDirty := s.stateObjectsDirty[addr]
|
||||||
|
switch {
|
||||||
|
case stateObject.suicided || (isDirty && deleteEmptyObjects && stateObject.empty()):
|
||||||
// If the object has been removed, don't bother syncing it
|
// If the object has been removed, don't bother syncing it
|
||||||
// and just mark it for deletion in the trie.
|
// and just mark it for deletion in the trie.
|
||||||
s.deleteStateObject(stateObject)
|
s.deleteStateObject(stateObject)
|
||||||
} else if _, ok := s.stateObjectsDirty[addr]; ok {
|
case isDirty:
|
||||||
// Write any contract code associated with the state object
|
// Write any contract code associated with the state object
|
||||||
if stateObject.code != nil && stateObject.dirtyCode {
|
if stateObject.code != nil && stateObject.dirtyCode {
|
||||||
if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {
|
if err := dbw.Put(stateObject.CodeHash(), stateObject.code); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func TestUpdateLeaks(t *testing.T) {
|
||||||
if i%3 == 0 {
|
if i%3 == 0 {
|
||||||
state.SetCode(addr, []byte{i, i, i, i, i})
|
state.SetCode(addr, []byte{i, i, i, i, i})
|
||||||
}
|
}
|
||||||
state.IntermediateRoot()
|
state.IntermediateRoot(false)
|
||||||
}
|
}
|
||||||
// Ensure that no data was leaked into the database
|
// Ensure that no data was leaked into the database
|
||||||
for _, key := range db.Keys() {
|
for _, key := range db.Keys() {
|
||||||
|
|
@ -86,7 +86,7 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
modify(transState, common.Address{byte(i)}, i, 0)
|
modify(transState, common.Address{byte(i)}, i, 0)
|
||||||
}
|
}
|
||||||
// Write modifications to trie.
|
// Write modifications to trie.
|
||||||
transState.IntermediateRoot()
|
transState.IntermediateRoot(false)
|
||||||
|
|
||||||
// Overwrite all the data with new values in the transient database.
|
// Overwrite all the data with new values in the transient database.
|
||||||
for i := byte(0); i < 255; i++ {
|
for i := byte(0); i < 255; i++ {
|
||||||
|
|
@ -95,10 +95,10 @@ func TestIntermediateLeaks(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit and cross check the databases.
|
// Commit and cross check the databases.
|
||||||
if _, err := transState.Commit(); err != nil {
|
if _, err := transState.Commit(false); err != nil {
|
||||||
t.Fatalf("failed to commit transition state: %v", err)
|
t.Fatalf("failed to commit transition state: %v", err)
|
||||||
}
|
}
|
||||||
if _, err := finalState.Commit(); err != nil {
|
if _, err := finalState.Commit(false); err != nil {
|
||||||
t.Fatalf("failed to commit final state: %v", err)
|
t.Fatalf("failed to commit final state: %v", err)
|
||||||
}
|
}
|
||||||
for _, key := range finalDb.Keys() {
|
for _, key := range finalDb.Keys() {
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ func makeTestState() (ethdb.Database, common.Hash, []*testAccount) {
|
||||||
state.updateStateObject(obj)
|
state.updateStateObject(obj)
|
||||||
accounts = append(accounts, acc)
|
accounts = append(accounts, acc)
|
||||||
}
|
}
|
||||||
root, _ := state.Commit()
|
root, _ := state.Commit(false)
|
||||||
|
|
||||||
// Return the generated state
|
// Return the generated state
|
||||||
return db, root, accounts
|
return db, root, accounts
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -37,12 +38,12 @@ var (
|
||||||
//
|
//
|
||||||
// StateProcessor implements Processor.
|
// StateProcessor implements Processor.
|
||||||
type StateProcessor struct {
|
type StateProcessor struct {
|
||||||
config *ChainConfig
|
config *params.ChainConfig
|
||||||
bc *BlockChain
|
bc *BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateProcessor initialises a new StateProcessor.
|
// NewStateProcessor initialises a new StateProcessor.
|
||||||
func NewStateProcessor(config *ChainConfig, bc *BlockChain) *StateProcessor {
|
func NewStateProcessor(config *params.ChainConfig, bc *BlockChain) *StateProcessor {
|
||||||
return &StateProcessor{
|
return &StateProcessor{
|
||||||
config: config,
|
config: config,
|
||||||
bc: bc,
|
bc: bc,
|
||||||
|
|
@ -74,7 +75,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
statedb.StartRecord(tx.Hash(), block.Hash(), i)
|
||||||
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, totalUsedGas, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
receipts = append(receipts, receipt)
|
receipts = append(receipts, receipt)
|
||||||
allLogs = append(allLogs, logs...)
|
allLogs = append(allLogs, logs...)
|
||||||
|
|
@ -89,20 +90,24 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
//
|
//
|
||||||
// ApplyTransactions returns the generated receipts and vm logs during the
|
// ApplyTransactions returns the generated receipts and vm logs during the
|
||||||
// execution of the state transition phase.
|
// execution of the state transition phase.
|
||||||
func ApplyTransaction(config *ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, gp *GasPool, statedb *state.StateDB, header *types.Header, tx *types.Transaction, usedGas *big.Int, cfg vm.Config) (*types.Receipt, vm.Logs, *big.Int, error) {
|
||||||
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, tx, header, cfg), tx, gp)
|
msg, err := tx.AsMessage(types.MakeSigner(config, header.Number))
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, gas, err := ApplyMessage(NewEnv(statedb, config, bc, msg, header, cfg), msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the state with pending changes
|
// Update the state with pending changes
|
||||||
usedGas.Add(usedGas, gas)
|
usedGas.Add(usedGas, gas)
|
||||||
receipt := types.NewReceipt(statedb.IntermediateRoot().Bytes(), usedGas)
|
receipt := types.NewReceipt(statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes(), usedGas)
|
||||||
receipt.TxHash = tx.Hash()
|
receipt.TxHash = tx.Hash()
|
||||||
receipt.GasUsed = new(big.Int).Set(gas)
|
receipt.GasUsed = new(big.Int).Set(gas)
|
||||||
if MessageCreatesContract(tx) {
|
if MessageCreatesContract(msg) {
|
||||||
from, _ := tx.From()
|
receipt.ContractAddress = crypto.CreateAddress(msg.From(), tx.Nonce())
|
||||||
receipt.ContractAddress = crypto.CreateAddress(from, tx.Nonce())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logs := statedb.GetLogs(tx.Hash())
|
logs := statedb.GetLogs(tx.Hash())
|
||||||
|
|
|
||||||
|
|
@ -62,8 +62,8 @@ type StateTransition struct {
|
||||||
|
|
||||||
// Message represents a message sent to a contract.
|
// Message represents a message sent to a contract.
|
||||||
type Message interface {
|
type Message interface {
|
||||||
From() (common.Address, error)
|
From() common.Address
|
||||||
FromFrontier() (common.Address, error)
|
//FromFrontier() (common.Address, error)
|
||||||
To() *common.Address
|
To() *common.Address
|
||||||
|
|
||||||
GasPrice() *big.Int
|
GasPrice() *big.Int
|
||||||
|
|
@ -134,23 +134,12 @@ func ApplyMessage(env vm.Environment, msg Message, gp *GasPool) ([]byte, *big.In
|
||||||
return ret, gasUsed, err
|
return ret, gasUsed, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) from() (vm.Account, error) {
|
func (self *StateTransition) from() vm.Account {
|
||||||
var (
|
f := self.msg.From()
|
||||||
f common.Address
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if self.env.RuleSet().IsHomestead(self.env.BlockNumber()) {
|
|
||||||
f, err = self.msg.From()
|
|
||||||
} else {
|
|
||||||
f, err = self.msg.FromFrontier()
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !self.state.Exist(f) {
|
if !self.state.Exist(f) {
|
||||||
return self.state.CreateAccount(f), nil
|
return self.state.CreateAccount(f)
|
||||||
}
|
}
|
||||||
return self.state.GetAccount(f), nil
|
return self.state.GetAccount(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *StateTransition) to() vm.Account {
|
func (self *StateTransition) to() vm.Account {
|
||||||
|
|
@ -185,14 +174,11 @@ func (self *StateTransition) buyGas() error {
|
||||||
mgas := self.msg.Gas()
|
mgas := self.msg.Gas()
|
||||||
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
mgval := new(big.Int).Mul(mgas, self.gasPrice)
|
||||||
|
|
||||||
sender, err := self.from()
|
sender := self.from()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if sender.Balance().Cmp(mgval) < 0 {
|
if sender.Balance().Cmp(mgval) < 0 {
|
||||||
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
|
return fmt.Errorf("insufficient ETH for gas (%x). Req %v, has %v", sender.Address().Bytes()[:4], mgval, sender.Balance())
|
||||||
}
|
}
|
||||||
if err = self.gp.SubGas(mgas); err != nil {
|
if err := self.gp.SubGas(mgas); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
self.addGas(mgas)
|
self.addGas(mgas)
|
||||||
|
|
@ -203,10 +189,7 @@ func (self *StateTransition) buyGas() error {
|
||||||
|
|
||||||
func (self *StateTransition) preCheck() (err error) {
|
func (self *StateTransition) preCheck() (err error) {
|
||||||
msg := self.msg
|
msg := self.msg
|
||||||
sender, err := self.from()
|
sender := self.from()
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure this transaction's nonce is correct
|
// Make sure this transaction's nonce is correct
|
||||||
if msg.CheckNonce() {
|
if msg.CheckNonce() {
|
||||||
|
|
@ -232,9 +215,9 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
msg := self.msg
|
msg := self.msg
|
||||||
sender, _ := self.from() // err checked in preCheck
|
sender := self.from() // err checked in preCheck
|
||||||
|
|
||||||
homestead := self.env.RuleSet().IsHomestead(self.env.BlockNumber())
|
homestead := self.env.ChainConfig().IsHomestead(self.env.BlockNumber())
|
||||||
contractCreation := MessageCreatesContract(msg)
|
contractCreation := MessageCreatesContract(msg)
|
||||||
// Pay intrinsic gas
|
// Pay intrinsic gas
|
||||||
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
|
if err = self.useGas(IntrinsicGas(self.data, contractCreation, homestead)); err != nil {
|
||||||
|
|
@ -282,7 +265,7 @@ func (self *StateTransition) TransitionDb() (ret []byte, requiredGas, usedGas *b
|
||||||
func (self *StateTransition) refundGas() {
|
func (self *StateTransition) refundGas() {
|
||||||
// Return eth for remaining gas to the sender account,
|
// Return eth for remaining gas to the sender account,
|
||||||
// exchanged at the original rate.
|
// exchanged at the original rate.
|
||||||
sender, _ := self.from() // err already checked
|
sender := self.from() // err already checked
|
||||||
remaining := new(big.Int).Mul(self.gas, self.gasPrice)
|
remaining := new(big.Int).Mul(self.gas, self.gasPrice)
|
||||||
sender.AddBalance(remaining)
|
sender.AddBalance(remaining)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
"gopkg.in/karalabe/cookiejar.v2/collections/prque"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -83,7 +84,7 @@ type stateFn func() (*state.StateDB, error)
|
||||||
// current state) and future transactions. Transactions move between those
|
// current state) and future transactions. Transactions move between those
|
||||||
// two states over time as they are received and processed.
|
// two states over time as they are received and processed.
|
||||||
type TxPool struct {
|
type TxPool struct {
|
||||||
config *ChainConfig
|
config *params.ChainConfig
|
||||||
currentState stateFn // The state function which will allow us to do some pre checks
|
currentState stateFn // The state function which will allow us to do some pre checks
|
||||||
pendingState *state.ManagedState
|
pendingState *state.ManagedState
|
||||||
gasLimit func() *big.Int // The current gas limit function callback
|
gasLimit func() *big.Int // The current gas limit function callback
|
||||||
|
|
@ -91,6 +92,7 @@ type TxPool struct {
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
events event.Subscription
|
events event.Subscription
|
||||||
localTx *txSet
|
localTx *txSet
|
||||||
|
signer types.Signer
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
pending map[common.Address]*txList // All currently processable transactions
|
pending map[common.Address]*txList // All currently processable transactions
|
||||||
|
|
@ -104,9 +106,10 @@ type TxPool struct {
|
||||||
homestead bool
|
homestead bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTxPool(config *ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
|
func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, currentStateFn stateFn, gasLimitFn func() *big.Int) *TxPool {
|
||||||
pool := &TxPool{
|
pool := &TxPool{
|
||||||
config: config,
|
config: config,
|
||||||
|
signer: types.NewEIP155Signer(config.ChainId),
|
||||||
pending: make(map[common.Address]*txList),
|
pending: make(map[common.Address]*txList),
|
||||||
queue: make(map[common.Address]*txList),
|
queue: make(map[common.Address]*txList),
|
||||||
all: make(map[common.Hash]*types.Transaction),
|
all: make(map[common.Hash]*types.Transaction),
|
||||||
|
|
@ -138,8 +141,10 @@ func (pool *TxPool) eventLoop() {
|
||||||
switch ev := ev.Data.(type) {
|
switch ev := ev.Data.(type) {
|
||||||
case ChainHeadEvent:
|
case ChainHeadEvent:
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
if ev.Block != nil && pool.config.IsHomestead(ev.Block.Number()) {
|
if ev.Block != nil {
|
||||||
pool.homestead = true
|
if pool.config.IsHomestead(ev.Block.Number()) {
|
||||||
|
pool.homestead = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pool.resetState()
|
pool.resetState()
|
||||||
|
|
@ -271,7 +276,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
from, err := tx.From()
|
from, err := types.Sender(pool.signer, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ErrInvalidSender
|
return ErrInvalidSender
|
||||||
}
|
}
|
||||||
|
|
@ -306,7 +311,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction) error {
|
||||||
return ErrInsufficientFunds
|
return ErrInsufficientFunds
|
||||||
}
|
}
|
||||||
|
|
||||||
intrGas := IntrinsicGas(tx.Data(), MessageCreatesContract(tx), pool.homestead)
|
intrGas := IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)
|
||||||
if tx.Gas().Cmp(intrGas) < 0 {
|
if tx.Gas().Cmp(intrGas) < 0 {
|
||||||
return ErrIntrinsicGas
|
return ErrIntrinsicGas
|
||||||
}
|
}
|
||||||
|
|
@ -335,7 +340,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
|
||||||
if to := tx.To(); to != nil {
|
if to := tx.To(); to != nil {
|
||||||
rcpt = common.Bytes2Hex(to[:4])
|
rcpt = common.Bytes2Hex(to[:4])
|
||||||
}
|
}
|
||||||
from, _ := tx.From() // from already verified during tx validation
|
from, _ := types.Sender(pool.signer, tx) // from already verified during tx validation
|
||||||
glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash)
|
glog.Infof("(t) 0x%x => %s (%v) %x\n", from[:4], rcpt, tx.Value, hash)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -346,7 +351,7 @@ func (pool *TxPool) add(tx *types.Transaction) error {
|
||||||
// Note, this method assumes the pool lock is held!
|
// Note, this method assumes the pool lock is held!
|
||||||
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
|
func (pool *TxPool) enqueueTx(hash common.Hash, tx *types.Transaction) {
|
||||||
// Try to insert the transaction into the future queue
|
// Try to insert the transaction into the future queue
|
||||||
from, _ := tx.From() // already validated
|
from, _ := types.Sender(pool.signer, tx) // already validated
|
||||||
if pool.queue[from] == nil {
|
if pool.queue[from] == nil {
|
||||||
pool.queue[from] = newTxList(false)
|
pool.queue[from] = newTxList(false)
|
||||||
}
|
}
|
||||||
|
|
@ -458,7 +463,7 @@ func (pool *TxPool) removeTx(hash common.Hash) {
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
addr, _ := tx.From() // already validated during insertion
|
addr, _ := types.Sender(pool.signer, tx) // already validated during insertion
|
||||||
|
|
||||||
// Remove it from the list of known transactions
|
// Remove it from the list of known transactions
|
||||||
delete(pool.all, hash)
|
delete(pool.all, hash)
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
func transaction(nonce uint64, gaslimit *big.Int, key *ecdsa.PrivateKey) *types.Transaction {
|
||||||
tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(key)
|
tx, _ := types.NewTransaction(nonce, common.Address{}, big.NewInt(100), gaslimit, big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,6 +47,10 @@ func setupTxPool() (*TxPool, *ecdsa.PrivateKey) {
|
||||||
return newPool, key
|
return newPool, key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func deriveSender(tx *types.Transaction) (common.Address, error) {
|
||||||
|
return types.Sender(types.HomesteadSigner{}, tx)
|
||||||
|
}
|
||||||
|
|
||||||
func TestInvalidTransactions(t *testing.T) {
|
func TestInvalidTransactions(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
|
|
||||||
|
|
@ -55,7 +59,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||||
t.Error("expected", ErrNonExistentAccount)
|
t.Error("expected", ErrNonExistentAccount)
|
||||||
}
|
}
|
||||||
|
|
||||||
from, _ := tx.From()
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1))
|
currentState.AddBalance(from, big.NewInt(1))
|
||||||
if err := pool.Add(tx); err != ErrInsufficientFunds {
|
if err := pool.Add(tx); err != ErrInsufficientFunds {
|
||||||
|
|
@ -90,7 +94,7 @@ func TestInvalidTransactions(t *testing.T) {
|
||||||
func TestTransactionQueue(t *testing.T) {
|
func TestTransactionQueue(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
tx := transaction(0, big.NewInt(100), key)
|
tx := transaction(0, big.NewInt(100), key)
|
||||||
from, _ := tx.From()
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000))
|
currentState.AddBalance(from, big.NewInt(1000))
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
|
|
@ -101,7 +105,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
tx = transaction(1, big.NewInt(100), key)
|
tx = transaction(1, big.NewInt(100), key)
|
||||||
from, _ = tx.From()
|
from, _ = deriveSender(tx)
|
||||||
currentState.SetNonce(from, 2)
|
currentState.SetNonce(from, 2)
|
||||||
pool.enqueueTx(tx.Hash(), tx)
|
pool.enqueueTx(tx.Hash(), tx)
|
||||||
pool.promoteExecutables()
|
pool.promoteExecutables()
|
||||||
|
|
@ -117,7 +121,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
tx1 := transaction(0, big.NewInt(100), key)
|
tx1 := transaction(0, big.NewInt(100), key)
|
||||||
tx2 := transaction(10, big.NewInt(100), key)
|
tx2 := transaction(10, big.NewInt(100), key)
|
||||||
tx3 := transaction(11, big.NewInt(100), key)
|
tx3 := transaction(11, big.NewInt(100), key)
|
||||||
from, _ = tx1.From()
|
from, _ = deriveSender(tx1)
|
||||||
currentState, _ = pool.currentState()
|
currentState, _ = pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000))
|
currentState.AddBalance(from, big.NewInt(1000))
|
||||||
pool.enqueueTx(tx1.Hash(), tx1)
|
pool.enqueueTx(tx1.Hash(), tx1)
|
||||||
|
|
@ -137,7 +141,7 @@ func TestTransactionQueue(t *testing.T) {
|
||||||
func TestRemoveTx(t *testing.T) {
|
func TestRemoveTx(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
tx := transaction(0, big.NewInt(100), key)
|
tx := transaction(0, big.NewInt(100), key)
|
||||||
from, _ := tx.From()
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1))
|
currentState.AddBalance(from, big.NewInt(1))
|
||||||
|
|
||||||
|
|
@ -161,8 +165,8 @@ func TestRemoveTx(t *testing.T) {
|
||||||
func TestNegativeValue(t *testing.T) {
|
func TestNegativeValue(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
|
|
||||||
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(key)
|
tx, _ := types.NewTransaction(0, common.Address{}, big.NewInt(-1), big.NewInt(100), big.NewInt(1), nil).SignECDSA(types.HomesteadSigner{}, key)
|
||||||
from, _ := tx.From()
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1))
|
currentState.AddBalance(from, big.NewInt(1))
|
||||||
if err := pool.Add(tx); err != ErrNegativeValue {
|
if err := pool.Add(tx); err != ErrNegativeValue {
|
||||||
|
|
@ -209,9 +213,10 @@ func TestTransactionDoubleNonce(t *testing.T) {
|
||||||
}
|
}
|
||||||
resetState()
|
resetState()
|
||||||
|
|
||||||
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(key)
|
signer := types.HomesteadSigner{}
|
||||||
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(key)
|
tx1, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(100000), big.NewInt(1), nil).SignECDSA(signer, key)
|
||||||
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(key)
|
tx2, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(2), nil).SignECDSA(signer, key)
|
||||||
|
tx3, _ := types.NewTransaction(0, common.Address{}, big.NewInt(100), big.NewInt(1000000), big.NewInt(1), nil).SignECDSA(signer, key)
|
||||||
|
|
||||||
// Add the first two transaction, ensure higher priced stays only
|
// Add the first two transaction, ensure higher priced stays only
|
||||||
if err := pool.add(tx1); err != nil {
|
if err := pool.add(tx1); err != nil {
|
||||||
|
|
@ -287,7 +292,7 @@ func TestNonceRecovery(t *testing.T) {
|
||||||
func TestRemovedTxEvent(t *testing.T) {
|
func TestRemovedTxEvent(t *testing.T) {
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
tx := transaction(0, big.NewInt(1000000), key)
|
tx := transaction(0, big.NewInt(1000000), key)
|
||||||
from, _ := tx.From()
|
from, _ := deriveSender(tx)
|
||||||
currentState, _ := pool.currentState()
|
currentState, _ := pool.currentState()
|
||||||
currentState.AddBalance(from, big.NewInt(1000000000000))
|
currentState.AddBalance(from, big.NewInt(1000000000000))
|
||||||
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
pool.eventMux.Post(RemovedTransactionEvent{types.Transactions{tx}})
|
||||||
|
|
@ -305,7 +310,7 @@ func TestRemovedTxEvent(t *testing.T) {
|
||||||
func TestTransactionDropping(t *testing.T) {
|
func TestTransactionDropping(t *testing.T) {
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000))
|
state.AddBalance(account, big.NewInt(1000))
|
||||||
|
|
@ -369,7 +374,7 @@ func TestTransactionDropping(t *testing.T) {
|
||||||
func TestTransactionPostponing(t *testing.T) {
|
func TestTransactionPostponing(t *testing.T) {
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000))
|
state.AddBalance(account, big.NewInt(1000))
|
||||||
|
|
@ -443,7 +448,7 @@ func TestTransactionPostponing(t *testing.T) {
|
||||||
func TestTransactionQueueAccountLimiting(t *testing.T) {
|
func TestTransactionQueueAccountLimiting(t *testing.T) {
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
@ -531,7 +536,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
|
||||||
|
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
@ -555,7 +560,7 @@ func TestTransactionQueueTimeLimiting(t *testing.T) {
|
||||||
func TestTransactionPendingLimiting(t *testing.T) {
|
func TestTransactionPendingLimiting(t *testing.T) {
|
||||||
// Create a test account and fund it
|
// Create a test account and fund it
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
|
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
@ -585,7 +590,7 @@ func TestTransactionPendingLimitingEquivalency(t *testing.T) { testTransactionLi
|
||||||
func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
||||||
// Add a batch of transactions to a pool one by one
|
// Add a batch of transactions to a pool one by one
|
||||||
pool1, key1 := setupTxPool()
|
pool1, key1 := setupTxPool()
|
||||||
account1, _ := transaction(0, big.NewInt(0), key1).From()
|
account1, _ := deriveSender(transaction(0, big.NewInt(0), key1))
|
||||||
state1, _ := pool1.currentState()
|
state1, _ := pool1.currentState()
|
||||||
state1.AddBalance(account1, big.NewInt(1000000))
|
state1.AddBalance(account1, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
@ -596,7 +601,7 @@ func testTransactionLimitingEquivalency(t *testing.T, origin uint64) {
|
||||||
}
|
}
|
||||||
// Add a batch of transactions to a pool in one big batch
|
// Add a batch of transactions to a pool in one big batch
|
||||||
pool2, key2 := setupTxPool()
|
pool2, key2 := setupTxPool()
|
||||||
account2, _ := transaction(0, big.NewInt(0), key2).From()
|
account2, _ := deriveSender(transaction(0, big.NewInt(0), key2))
|
||||||
state2, _ := pool2.currentState()
|
state2, _ := pool2.currentState()
|
||||||
state2.AddBalance(account2, big.NewInt(1000000))
|
state2.AddBalance(account2, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
@ -717,7 +722,7 @@ func BenchmarkPendingDemotion10000(b *testing.B) { benchmarkPendingDemotion(b, 1
|
||||||
func benchmarkPendingDemotion(b *testing.B, size int) {
|
func benchmarkPendingDemotion(b *testing.B, size int) {
|
||||||
// Add a batch of transactions to a pool one by one
|
// Add a batch of transactions to a pool one by one
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
@ -741,7 +746,7 @@ func BenchmarkFuturePromotion10000(b *testing.B) { benchmarkFuturePromotion(b, 1
|
||||||
func benchmarkFuturePromotion(b *testing.B, size int) {
|
func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||||
// Add a batch of transactions to a pool one by one
|
// Add a batch of transactions to a pool one by one
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
@ -760,7 +765,7 @@ func benchmarkFuturePromotion(b *testing.B, size int) {
|
||||||
func BenchmarkPoolInsert(b *testing.B) {
|
func BenchmarkPoolInsert(b *testing.B) {
|
||||||
// Generate a batch of transactions to enqueue into the pool
|
// Generate a batch of transactions to enqueue into the pool
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
@ -783,7 +788,7 @@ func BenchmarkPoolBatchInsert10000(b *testing.B) { benchmarkPoolBatchInsert(b, 1
|
||||||
func benchmarkPoolBatchInsert(b *testing.B, size int) {
|
func benchmarkPoolBatchInsert(b *testing.B, size int) {
|
||||||
// Generate a batch of transactions to enqueue into the pool
|
// Generate a batch of transactions to enqueue into the pool
|
||||||
pool, key := setupTxPool()
|
pool, key := setupTxPool()
|
||||||
account, _ := transaction(0, big.NewInt(0), key).From()
|
account, _ := deriveSender(transaction(0, big.NewInt(0), key))
|
||||||
state, _ := pool.currentState()
|
state, _ := pool.currentState()
|
||||||
state.AddBalance(account, big.NewInt(1000000))
|
state.AddBalance(account, big.NewInt(1000000))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ func (n *BlockNonce) UnmarshalJSON(input []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Header represents Ethereum block headers.
|
// Header represents a block header in the Ethereum blockchain.
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ParentHash common.Hash // Hash to the previous block
|
ParentHash common.Hash // Hash to the previous block
|
||||||
UncleHash common.Hash // Uncles of this block
|
UncleHash common.Hash // Uncles of this block
|
||||||
|
|
@ -214,7 +214,7 @@ type Body struct {
|
||||||
Uncles []*Header
|
Uncles []*Header
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block represents a block in the Ethereum blockchain.
|
// Block represents an entire block in the Ethereum blockchain.
|
||||||
type Block struct {
|
type Block struct {
|
||||||
header *Header
|
header *Header
|
||||||
uncles []*Header
|
uncles []*Header
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -51,7 +52,11 @@ func TestBlockEncoding(t *testing.T) {
|
||||||
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
|
check("Size", block.Size(), common.StorageSize(len(blockEnc)))
|
||||||
|
|
||||||
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
|
tx1 := NewTransaction(0, common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), big.NewInt(10), big.NewInt(50000), big.NewInt(10), nil)
|
||||||
tx1, _ = tx1.WithSignature(common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
|
|
||||||
|
tx1, _ = tx1.WithSignature(HomesteadSigner{}, common.Hex2Bytes("9bea4c4daac7c7c52e093e6a4c35dbbcf8856f1af7b059ba20253e70848d094f8a8fae537ce25ed8cb5af9adac3f141af69bd515bd2ba031522df09b97dd72b11b"))
|
||||||
|
fmt.Println(block.Transactions()[0].Hash())
|
||||||
|
fmt.Println(tx1.data)
|
||||||
|
fmt.Println(tx1.Hash())
|
||||||
check("len(Transactions)", len(block.Transactions()), 1)
|
check("len(Transactions)", len(block.Transactions()), 1)
|
||||||
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
|
check("Transactions[0].Hash", block.Transactions()[0].Hash(), tx1.Hash())
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,10 +97,12 @@ var unmarshalTransactionTests = map[string]struct {
|
||||||
wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"),
|
wantHash: common.HexToHash("0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9"),
|
||||||
wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"),
|
wantFrom: common.HexToAddress("0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689"),
|
||||||
},
|
},
|
||||||
|
/* TODO skipping this test as this type can not be tested with the current signing approach
|
||||||
"bad signature fields": {
|
"bad signature fields": {
|
||||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
|
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","v":"0x58","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
|
||||||
wantError: ErrInvalidSig,
|
wantError: ErrInvalidSig,
|
||||||
},
|
},
|
||||||
|
*/
|
||||||
"missing signature v": {
|
"missing signature v": {
|
||||||
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
|
input: `{"blockHash":"0x0188a05dcc825bd1a05dab91bea0c03622542683446e56302eabb46097d4ae11","blockNumber":"0x1e478d","from":"0xf36c3f6c4a2ce8d353fb92d5cd10d19ce69ae689","gas":"0x15f90","gasPrice":"0x4a817c800","hash":"0xd91c08f1e27c5ce7e1f57d78d7c56a9ee446be07b9635d84d0475660ea8905e9","input":"0x","nonce":"0x58d","to":"0x88f252f674ac755feff877abf957d4aa05adce86","transactionIndex":"0x1","value":"0x19f0ec3ed71ec00","r":"0x53829f206c99b866672f987909d556cd1c2eb60e990a3425f65083977c14187b","s":"0x5cc52383e41c923ec7d63749c1f13a7236b540527ee5b9a78b3fb869a66f60e"}`,
|
||||||
wantError: errMissingTxSignatureFields,
|
wantError: errMissingTxSignatureFields,
|
||||||
|
|
@ -122,11 +124,12 @@ func TestUnmarshalTransaction(t *testing.T) {
|
||||||
if !checkError(t, name, err, test.wantError) {
|
if !checkError(t, name, err, test.wantError) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tx.Hash() != test.wantHash {
|
if tx.Hash() != test.wantHash {
|
||||||
t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash)
|
t.Errorf("test %q: got hash %x, want %x", name, tx.Hash(), test.wantHash)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
from, err := tx.From()
|
from, err := Sender(HomesteadSigner{}, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %q: From error %v", name, err)
|
t.Errorf("test %q: From error %v", name, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -36,8 +37,18 @@ var ErrInvalidSig = errors.New("invalid transaction v, r, s values")
|
||||||
var (
|
var (
|
||||||
errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields")
|
errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields")
|
||||||
errMissingTxFields = errors.New("missing required JSON transaction fields")
|
errMissingTxFields = errors.New("missing required JSON transaction fields")
|
||||||
|
errNoSigner = errors.New("missing signing methods")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// deriveSigner makes a *best* guess about which signer to use.
|
||||||
|
func deriveSigner(V *big.Int) Signer {
|
||||||
|
if V.BitLen() > 0 && isProtectedV(V) {
|
||||||
|
return EIP155Signer{chainId: deriveChainId(V)}
|
||||||
|
} else {
|
||||||
|
return HomesteadSigner{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type Transaction struct {
|
type Transaction struct {
|
||||||
data txdata
|
data txdata
|
||||||
// caches
|
// caches
|
||||||
|
|
@ -52,7 +63,7 @@ type txdata struct {
|
||||||
Recipient *common.Address `rlp:"nil"` // nil means contract creation
|
Recipient *common.Address `rlp:"nil"` // nil means contract creation
|
||||||
Amount *big.Int
|
Amount *big.Int
|
||||||
Payload []byte
|
Payload []byte
|
||||||
V byte // signature
|
V *big.Int // signature
|
||||||
R, S *big.Int // signature
|
R, S *big.Int // signature
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,40 +75,31 @@ type jsonTransaction struct {
|
||||||
Recipient *common.Address `json:"to"`
|
Recipient *common.Address `json:"to"`
|
||||||
Amount *hexBig `json:"value"`
|
Amount *hexBig `json:"value"`
|
||||||
Payload *hexBytes `json:"input"`
|
Payload *hexBytes `json:"input"`
|
||||||
V *hexUint64 `json:"v"`
|
V *hexBig `json:"v"`
|
||||||
R *hexBig `json:"r"`
|
R *hexBig `json:"r"`
|
||||||
S *hexBig `json:"s"`
|
S *hexBig `json:"s"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContractCreation creates a new transaction with no recipient.
|
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||||
func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data)
|
||||||
if len(data) > 0 {
|
|
||||||
data = common.CopyBytes(data)
|
|
||||||
}
|
|
||||||
return &Transaction{data: txdata{
|
|
||||||
AccountNonce: nonce,
|
|
||||||
Recipient: nil,
|
|
||||||
Amount: new(big.Int).Set(amount),
|
|
||||||
GasLimit: new(big.Int).Set(gasLimit),
|
|
||||||
Price: new(big.Int).Set(gasPrice),
|
|
||||||
Payload: data,
|
|
||||||
R: new(big.Int),
|
|
||||||
S: new(big.Int),
|
|
||||||
}}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTransaction creates a new transaction with the given fields.
|
func NewContractCreation(nonce uint64, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||||
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newTransaction(nonce uint64, to *common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
|
||||||
if len(data) > 0 {
|
if len(data) > 0 {
|
||||||
data = common.CopyBytes(data)
|
data = common.CopyBytes(data)
|
||||||
}
|
}
|
||||||
d := txdata{
|
d := txdata{
|
||||||
AccountNonce: nonce,
|
AccountNonce: nonce,
|
||||||
Recipient: &to,
|
Recipient: to,
|
||||||
Payload: data,
|
Payload: data,
|
||||||
Amount: new(big.Int),
|
Amount: new(big.Int),
|
||||||
GasLimit: new(big.Int),
|
GasLimit: new(big.Int),
|
||||||
Price: new(big.Int),
|
Price: new(big.Int),
|
||||||
|
V: new(big.Int),
|
||||||
R: new(big.Int),
|
R: new(big.Int),
|
||||||
S: new(big.Int),
|
S: new(big.Int),
|
||||||
}
|
}
|
||||||
|
|
@ -110,9 +112,42 @@ func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice
|
||||||
if gasPrice != nil {
|
if gasPrice != nil {
|
||||||
d.Price.Set(gasPrice)
|
d.Price.Set(gasPrice)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Transaction{data: d}
|
return &Transaction{data: d}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func pickSigner(rules params.Rules) Signer {
|
||||||
|
var signer Signer
|
||||||
|
switch {
|
||||||
|
case rules.IsEIP155:
|
||||||
|
signer = NewEIP155Signer(rules.ChainId)
|
||||||
|
case rules.IsHomestead:
|
||||||
|
signer = HomesteadSigner{}
|
||||||
|
default:
|
||||||
|
signer = FrontierSigner{}
|
||||||
|
}
|
||||||
|
return signer
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChainId returns which chain id this transaction was signed for (if at all)
|
||||||
|
func (tx *Transaction) ChainId() *big.Int {
|
||||||
|
return deriveChainId(tx.data.V)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Protected returns whether the transaction is pretected from replay protection
|
||||||
|
func (tx *Transaction) Protected() bool {
|
||||||
|
return isProtectedV(tx.data.V)
|
||||||
|
}
|
||||||
|
|
||||||
|
func isProtectedV(V *big.Int) bool {
|
||||||
|
if V.BitLen() <= 8 {
|
||||||
|
v := V.Uint64()
|
||||||
|
return v != 27 && v != 28
|
||||||
|
}
|
||||||
|
// anything not 27 or 28 are considered unprotected
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// DecodeRLP implements rlp.Encoder
|
// DecodeRLP implements rlp.Encoder
|
||||||
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
func (tx *Transaction) EncodeRLP(w io.Writer) error {
|
||||||
return rlp.Encode(w, &tx.data)
|
return rlp.Encode(w, &tx.data)
|
||||||
|
|
@ -125,12 +160,13 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
|
tx.size.Store(common.StorageSize(rlp.ListSize(size)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalJSON encodes transactions into the web3 RPC response block format.
|
// MarshalJSON encodes transactions into the web3 RPC response block format.
|
||||||
func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||||
hash, v := tx.Hash(), uint64(tx.data.V)
|
hash := tx.Hash()
|
||||||
|
|
||||||
return json.Marshal(&jsonTransaction{
|
return json.Marshal(&jsonTransaction{
|
||||||
Hash: &hash,
|
Hash: &hash,
|
||||||
|
|
@ -140,7 +176,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||||
Recipient: tx.data.Recipient,
|
Recipient: tx.data.Recipient,
|
||||||
Amount: (*hexBig)(tx.data.Amount),
|
Amount: (*hexBig)(tx.data.Amount),
|
||||||
Payload: (*hexBytes)(&tx.data.Payload),
|
Payload: (*hexBytes)(&tx.data.Payload),
|
||||||
V: (*hexUint64)(&v),
|
V: (*hexBig)(tx.data.V),
|
||||||
R: (*hexBig)(tx.data.R),
|
R: (*hexBig)(tx.data.R),
|
||||||
S: (*hexBig)(tx.data.S),
|
S: (*hexBig)(tx.data.S),
|
||||||
})
|
})
|
||||||
|
|
@ -159,9 +195,17 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
if dec.V == nil || dec.R == nil || dec.S == nil {
|
if dec.V == nil || dec.R == nil || dec.S == nil {
|
||||||
return errMissingTxSignatureFields
|
return errMissingTxSignatureFields
|
||||||
}
|
}
|
||||||
if !crypto.ValidateSignatureValues(byte(*dec.V), (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
|
|
||||||
|
var V byte
|
||||||
|
if isProtectedV((*big.Int)(dec.V)) {
|
||||||
|
V = normaliseV(NewEIP155Signer(deriveChainId((*big.Int)(dec.V))), (*big.Int)(dec.V))
|
||||||
|
} else {
|
||||||
|
V = byte(((*big.Int)(dec.V)).Uint64())
|
||||||
|
}
|
||||||
|
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
|
||||||
return ErrInvalidSig
|
return ErrInvalidSig
|
||||||
}
|
}
|
||||||
|
|
||||||
if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
|
if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
|
||||||
return errMissingTxFields
|
return errMissingTxFields
|
||||||
}
|
}
|
||||||
|
|
@ -175,7 +219,7 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||||
GasLimit: (*big.Int)(dec.GasLimit),
|
GasLimit: (*big.Int)(dec.GasLimit),
|
||||||
Price: (*big.Int)(dec.Price),
|
Price: (*big.Int)(dec.Price),
|
||||||
Payload: *dec.Payload,
|
Payload: *dec.Payload,
|
||||||
V: byte(*dec.V),
|
V: (*big.Int)(dec.V),
|
||||||
R: (*big.Int)(dec.R),
|
R: (*big.Int)(dec.R),
|
||||||
S: (*big.Int)(dec.S),
|
S: (*big.Int)(dec.S),
|
||||||
}
|
}
|
||||||
|
|
@ -211,15 +255,8 @@ func (tx *Transaction) Hash() common.Hash {
|
||||||
|
|
||||||
// SigHash returns the hash to be signed by the sender.
|
// SigHash returns the hash to be signed by the sender.
|
||||||
// It does not uniquely identify the transaction.
|
// It does not uniquely identify the transaction.
|
||||||
func (tx *Transaction) SigHash() common.Hash {
|
func (tx *Transaction) SigHash(signer Signer) common.Hash {
|
||||||
return rlpHash([]interface{}{
|
return signer.Hash(tx)
|
||||||
tx.data.AccountNonce,
|
|
||||||
tx.data.Price,
|
|
||||||
tx.data.GasLimit,
|
|
||||||
tx.data.Recipient,
|
|
||||||
tx.data.Amount,
|
|
||||||
tx.data.Payload,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) Size() common.StorageSize {
|
func (tx *Transaction) Size() common.StorageSize {
|
||||||
|
|
@ -232,6 +269,7 @@ func (tx *Transaction) Size() common.StorageSize {
|
||||||
return common.StorageSize(c)
|
return common.StorageSize(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
// From returns the address derived from the signature (V, R, S) using secp256k1
|
// From returns the address derived from the signature (V, R, S) using secp256k1
|
||||||
// elliptic curve and an error if it failed deriving or upon an incorrect
|
// elliptic curve and an error if it failed deriving or upon an incorrect
|
||||||
// signature.
|
// signature.
|
||||||
|
|
@ -247,32 +285,15 @@ func (tx *Transaction) Size() common.StorageSize {
|
||||||
// both txs before and after the first homestead block. Signatures
|
// both txs before and after the first homestead block. Signatures
|
||||||
// valid in homestead are a subset of valid ones in Frontier)
|
// valid in homestead are a subset of valid ones in Frontier)
|
||||||
func (tx *Transaction) From() (common.Address, error) {
|
func (tx *Transaction) From() (common.Address, error) {
|
||||||
return doFrom(tx, true)
|
if tx.signer == nil {
|
||||||
}
|
return common.Address{}, errNoSigner
|
||||||
|
}
|
||||||
|
|
||||||
// FromFrontier returns the address derived from the signature (V, R, S) using
|
|
||||||
// secp256k1 elliptic curve and an error if it failed deriving or upon an
|
|
||||||
// incorrect signature.
|
|
||||||
//
|
|
||||||
// FromFrantier uses the frontier consensus rules to determine whether the
|
|
||||||
// signature is valid.
|
|
||||||
//
|
|
||||||
// FromFrontier caches the address, allowing it to be used regardless of
|
|
||||||
// Frontier / Homestead. however, the first time called it runs
|
|
||||||
// signature validations, so we need two versions. This makes it
|
|
||||||
// easier to ensure backwards compatibility of things like package rpc
|
|
||||||
// where eth_getblockbynumber uses tx.From() and needs to work for
|
|
||||||
// both txs before and after the first homestead block. Signatures
|
|
||||||
// valid in homestead are a subset of valid ones in Frontier)
|
|
||||||
func (tx *Transaction) FromFrontier() (common.Address, error) {
|
|
||||||
return doFrom(tx, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
|
|
||||||
if from := tx.from.Load(); from != nil {
|
if from := tx.from.Load(); from != nil {
|
||||||
return from.(common.Address), nil
|
return from.(common.Address), nil
|
||||||
}
|
}
|
||||||
pubkey, err := tx.publicKey(homestead)
|
|
||||||
|
pubkey, err := tx.signer.PublicKey(tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Address{}, err
|
return common.Address{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -282,6 +303,52 @@ func doFrom(tx *Transaction, homestead bool) (common.Address, error) {
|
||||||
return addr, nil
|
return addr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
||||||
|
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int, err error) {
|
||||||
|
if tx.signer == nil {
|
||||||
|
return 0, nil, nil,errNoSigner
|
||||||
|
}
|
||||||
|
|
||||||
|
return normaliseV(tx.signer, tx.data.V), new(big.Int).Set(tx.data.R),new(big.Int).Set(tx.data.S), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
// AsMessage returns the transaction as a core.Message.
|
||||||
|
//
|
||||||
|
// AsMessage requires a signer to derive the sender.
|
||||||
|
//
|
||||||
|
// XXX Rename message to something less arbitrary?
|
||||||
|
func (tx *Transaction) AsMessage(s Signer) (Message, error) {
|
||||||
|
msg := Message{
|
||||||
|
nonce: tx.data.AccountNonce,
|
||||||
|
price: new(big.Int).Set(tx.data.Price),
|
||||||
|
gasLimit: new(big.Int).Set(tx.data.GasLimit),
|
||||||
|
to: tx.data.Recipient,
|
||||||
|
amount: tx.data.Amount,
|
||||||
|
data: tx.data.Payload,
|
||||||
|
checkNonce: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
var err error
|
||||||
|
msg.from, err = Sender(s, tx)
|
||||||
|
return msg, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignECDSA signs the transaction using the given signer and private key
|
||||||
|
//
|
||||||
|
// XXX This only makes for a nice API: NewTx(...).SignECDSA(signer, prv). Should
|
||||||
|
// we keep this?
|
||||||
|
func (tx *Transaction) SignECDSA(signer Signer, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
return signer.SignECDSA(tx, prv)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignature returns a new transaction with the given signature.
|
||||||
|
// This signature needs to be formatted as described in the yellow paper (v+27).
|
||||||
|
func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, error) {
|
||||||
|
return signer.WithSignature(tx, sig)
|
||||||
|
}
|
||||||
|
|
||||||
// Cost returns amount + gasprice * gaslimit.
|
// Cost returns amount + gasprice * gaslimit.
|
||||||
func (tx *Transaction) Cost() *big.Int {
|
func (tx *Transaction) Cost() *big.Int {
|
||||||
total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit)
|
total := new(big.Int).Mul(tx.data.Price, tx.data.GasLimit)
|
||||||
|
|
@ -289,61 +356,18 @@ func (tx *Transaction) Cost() *big.Int {
|
||||||
return total
|
return total
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
func (tx *Transaction) RawSignatureValues() (*big.Int, *big.Int, *big.Int) {
|
||||||
func (tx *Transaction) SignatureValues() (v byte, r *big.Int, s *big.Int) {
|
return tx.data.V, tx.data.R, tx.data.S
|
||||||
return tx.data.V, new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) publicKey(homestead bool) ([]byte, error) {
|
|
||||||
if !crypto.ValidateSignatureValues(tx.data.V, tx.data.R, tx.data.S, homestead) {
|
|
||||||
return nil, ErrInvalidSig
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode the signature in uncompressed format
|
|
||||||
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
|
|
||||||
sig := make([]byte, 65)
|
|
||||||
copy(sig[32-len(r):32], r)
|
|
||||||
copy(sig[64-len(s):64], s)
|
|
||||||
sig[64] = tx.data.V - 27
|
|
||||||
|
|
||||||
// recover the public key from the signature
|
|
||||||
hash := tx.SigHash()
|
|
||||||
pub, err := crypto.Ecrecover(hash[:], sig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if len(pub) == 0 || pub[0] != 4 {
|
|
||||||
return nil, errors.New("invalid public key")
|
|
||||||
}
|
|
||||||
return pub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithSignature returns a new transaction with the given signature.
|
|
||||||
// This signature needs to be formatted as described in the yellow paper (v+27).
|
|
||||||
func (tx *Transaction) WithSignature(sig []byte) (*Transaction, error) {
|
|
||||||
if len(sig) != 65 {
|
|
||||||
panic(fmt.Sprintf("wrong size for signature: got %d, want 65", len(sig)))
|
|
||||||
}
|
|
||||||
cpy := &Transaction{data: tx.data}
|
|
||||||
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
|
||||||
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
|
||||||
cpy.data.V = sig[64]
|
|
||||||
return cpy, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tx *Transaction) SignECDSA(prv *ecdsa.PrivateKey) (*Transaction, error) {
|
|
||||||
h := tx.SigHash()
|
|
||||||
sig, err := crypto.SignEthereum(h[:], prv)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return tx.WithSignature(sig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *Transaction) String() string {
|
func (tx *Transaction) String() string {
|
||||||
|
// make a best guess about the signer and use that to derive
|
||||||
|
// the sender.
|
||||||
|
signer := deriveSigner(tx.data.V)
|
||||||
|
|
||||||
var from, to string
|
var from, to string
|
||||||
if f, err := tx.From(); err != nil {
|
if f, err := Sender(signer, tx); err != nil { // derive but don't cache
|
||||||
from = "[invalid sender]"
|
from = "[invalid sender: invalid sig]"
|
||||||
} else {
|
} else {
|
||||||
from = fmt.Sprintf("%x", f[:])
|
from = fmt.Sprintf("%x", f[:])
|
||||||
}
|
}
|
||||||
|
|
@ -485,8 +509,9 @@ func (t *TransactionsByPriceAndNonce) Peek() *Transaction {
|
||||||
|
|
||||||
// Shift replaces the current best head with the next one from the same account.
|
// Shift replaces the current best head with the next one from the same account.
|
||||||
func (t *TransactionsByPriceAndNonce) Shift() {
|
func (t *TransactionsByPriceAndNonce) Shift() {
|
||||||
acc, _ := t.heads[0].From() // we only sort valid txs so this cannot fail
|
signer := deriveSigner(t.heads[0].data.V)
|
||||||
|
// derive signer but don't cache.
|
||||||
|
acc, _ := Sender(signer, t.heads[0]) // we only sort valid txs so this cannot fail
|
||||||
if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
|
if txs, ok := t.txs[acc]; ok && len(txs) > 0 {
|
||||||
t.heads[0], t.txs[acc] = txs[0], txs[1:]
|
t.heads[0], t.txs[acc] = txs[0], txs[1:]
|
||||||
heap.Fix(&t.heads, 0)
|
heap.Fix(&t.heads, 0)
|
||||||
|
|
@ -501,3 +526,37 @@ func (t *TransactionsByPriceAndNonce) Shift() {
|
||||||
func (t *TransactionsByPriceAndNonce) Pop() {
|
func (t *TransactionsByPriceAndNonce) Pop() {
|
||||||
heap.Pop(&t.heads)
|
heap.Pop(&t.heads)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Message is a fully derived transaction and implements core.Message
|
||||||
|
//
|
||||||
|
// NOTE: In a future PR this will be removed.
|
||||||
|
type Message struct {
|
||||||
|
to *common.Address
|
||||||
|
from common.Address
|
||||||
|
nonce uint64
|
||||||
|
amount, price, gasLimit *big.Int
|
||||||
|
data []byte
|
||||||
|
checkNonce bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewMessage(from common.Address, to *common.Address, nonce uint64, amount, gasLimit, price *big.Int, data []byte, checkNonce bool) Message {
|
||||||
|
return Message{
|
||||||
|
from: from,
|
||||||
|
to: to,
|
||||||
|
nonce: nonce,
|
||||||
|
amount: amount,
|
||||||
|
price: price,
|
||||||
|
gasLimit: gasLimit,
|
||||||
|
data: data,
|
||||||
|
checkNonce: checkNonce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Message) From() common.Address { return m.from }
|
||||||
|
func (m Message) To() *common.Address { return m.to }
|
||||||
|
func (m Message) GasPrice() *big.Int { return m.price }
|
||||||
|
func (m Message) Value() *big.Int { return m.amount }
|
||||||
|
func (m Message) Gas() *big.Int { return m.gasLimit }
|
||||||
|
func (m Message) Nonce() uint64 { return m.nonce }
|
||||||
|
func (m Message) Data() []byte { return m.data }
|
||||||
|
func (m Message) CheckNonce() bool { return m.checkNonce }
|
||||||
|
|
|
||||||
362
core/types/transaction_signing.go
Normal file
362
core/types/transaction_signing.go
Normal file
|
|
@ -0,0 +1,362 @@
|
||||||
|
// Copyright 2016 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrInvalidChainId = errors.New("invalid chaid id for signer")
|
||||||
|
|
||||||
|
// sigCache is used to cache the derived sender and contains
|
||||||
|
// the signer used to derive it.
|
||||||
|
type sigCache struct {
|
||||||
|
signer Signer
|
||||||
|
from common.Address
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeSigner returns a Signer based on the given chain config and block number.
|
||||||
|
func MakeSigner(config *params.ChainConfig, blockNumber *big.Int) Signer {
|
||||||
|
var signer Signer
|
||||||
|
switch {
|
||||||
|
case config.IsEIP155(blockNumber):
|
||||||
|
signer = NewEIP155Signer(config.ChainId)
|
||||||
|
case config.IsHomestead(blockNumber):
|
||||||
|
signer = HomesteadSigner{}
|
||||||
|
default:
|
||||||
|
signer = FrontierSigner{}
|
||||||
|
}
|
||||||
|
return signer
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignECDSA signs the transaction using the given signer and private key
|
||||||
|
func SignECDSA(s Signer, tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
h := s.Hash(tx)
|
||||||
|
sig, err := crypto.SignEthereum(h[:], prv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.WithSignature(tx, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sender derives the sender from the tx using the signer derivation
|
||||||
|
// functions.
|
||||||
|
|
||||||
|
// Sender returns the address derived from the signature (V, R, S) using secp256k1
|
||||||
|
// elliptic curve and an error if it failed deriving or upon an incorrect
|
||||||
|
// signature.
|
||||||
|
//
|
||||||
|
// Sender may cache the address, allowing it to be used regardless of
|
||||||
|
// signing method. The cache is invalidated if the cached signer does
|
||||||
|
// not match the signer used in the current call.
|
||||||
|
func Sender(signer Signer, tx *Transaction) (common.Address, error) {
|
||||||
|
if sc := tx.from.Load(); sc != nil {
|
||||||
|
sigCache := sc.(sigCache)
|
||||||
|
// If the signer used to derive from in a previous
|
||||||
|
// call is not the same as used current, invalidate
|
||||||
|
// the cache.
|
||||||
|
if sigCache.signer.Equal(signer) {
|
||||||
|
return sigCache.from, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pubkey, err := signer.PublicKey(tx)
|
||||||
|
if err != nil {
|
||||||
|
return common.Address{}, err
|
||||||
|
}
|
||||||
|
var addr common.Address
|
||||||
|
copy(addr[:], crypto.Keccak256(pubkey[1:])[12:])
|
||||||
|
tx.from.Store(sigCache{signer: signer, from: addr})
|
||||||
|
return addr, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignatureValues returns the ECDSA signature values contained in the transaction.
|
||||||
|
func SignatureValues(signer Signer, tx *Transaction) (v byte, r *big.Int, s *big.Int) {
|
||||||
|
return normaliseV(signer, tx.data.V), new(big.Int).Set(tx.data.R), new(big.Int).Set(tx.data.S)
|
||||||
|
}
|
||||||
|
|
||||||
|
type Signer interface {
|
||||||
|
// Hash returns the rlp encoded hash for signatures
|
||||||
|
Hash(tx *Transaction) common.Hash
|
||||||
|
// PubilcKey returns the public key derived from the signature
|
||||||
|
PublicKey(tx *Transaction) ([]byte, error)
|
||||||
|
// SignECDSA signs the transaction with the given and returns a copy of the tx
|
||||||
|
SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error)
|
||||||
|
// WithSignature returns a copy of the transaction with the given signature
|
||||||
|
WithSignature(tx *Transaction, sig []byte) (*Transaction, error)
|
||||||
|
// Checks for equality on the signers
|
||||||
|
Equal(Signer) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// EIP155Transaction implements TransactionInterface using the
|
||||||
|
// EIP155 rules
|
||||||
|
type EIP155Signer struct {
|
||||||
|
HomesteadSigner
|
||||||
|
|
||||||
|
chainId, chainIdMul *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEIP155Signer(chainId *big.Int) EIP155Signer {
|
||||||
|
return EIP155Signer{
|
||||||
|
chainId: chainId,
|
||||||
|
chainIdMul: new(big.Int).Mul(chainId, big.NewInt(2)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP155Signer) Equal(s2 Signer) bool {
|
||||||
|
eip155, ok := s2.(EIP155Signer)
|
||||||
|
return ok && eip155.chainId.Cmp(s.chainId) == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP155Signer) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
return SignECDSA(s, tx, prv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP155Signer) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
|
// if the transaction is not protected fall back to homestead signer
|
||||||
|
if !tx.Protected() {
|
||||||
|
return (HomesteadSigner{}).PublicKey(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.ChainId().Cmp(s.chainId) != 0 {
|
||||||
|
return nil, ErrInvalidChainId
|
||||||
|
}
|
||||||
|
|
||||||
|
V := normaliseV(s, tx.data.V)
|
||||||
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
||||||
|
return nil, ErrInvalidSig
|
||||||
|
}
|
||||||
|
|
||||||
|
// encode the signature in uncompressed format
|
||||||
|
R, S := tx.data.R.Bytes(), tx.data.S.Bytes()
|
||||||
|
sig := make([]byte, 65)
|
||||||
|
copy(sig[32-len(R):32], R)
|
||||||
|
copy(sig[64-len(S):64], S)
|
||||||
|
sig[64] = V - 27
|
||||||
|
|
||||||
|
// recover the public key from the signature
|
||||||
|
hash := s.Hash(tx)
|
||||||
|
pub, err := crypto.Ecrecover(hash[:], sig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(pub) == 0 || pub[0] != 4 {
|
||||||
|
return nil, errors.New("invalid public key")
|
||||||
|
}
|
||||||
|
return pub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignature returns a new transaction with the given signature.
|
||||||
|
// This signature needs to be formatted as described in the yellow paper (v+27).
|
||||||
|
func (s EIP155Signer) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
|
if len(sig) != 65 {
|
||||||
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
}
|
||||||
|
|
||||||
|
cpy := &Transaction{data: tx.data}
|
||||||
|
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
||||||
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
||||||
|
if s.chainId.BitLen() > 0 {
|
||||||
|
cpy.data.V = big.NewInt(int64(sig[64] - 27 + 35))
|
||||||
|
cpy.data.V.Add(cpy.data.V, s.chainIdMul)
|
||||||
|
}
|
||||||
|
return cpy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns the hash to be signed by the sender.
|
||||||
|
// It does not uniquely identify the transaction.
|
||||||
|
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
||||||
|
return rlpHash([]interface{}{
|
||||||
|
tx.data.AccountNonce,
|
||||||
|
tx.data.Price,
|
||||||
|
tx.data.GasLimit,
|
||||||
|
tx.data.Recipient,
|
||||||
|
tx.data.Amount,
|
||||||
|
tx.data.Payload,
|
||||||
|
s.chainId, uint(0), uint(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s EIP155Signer) SigECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
h := s.Hash(tx)
|
||||||
|
sig, err := crypto.SignEthereum(h[:], prv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return s.WithSignature(tx, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HomesteadTransaction implements TransactionInterface using the
|
||||||
|
// homestead rules.
|
||||||
|
type HomesteadSigner struct{ FrontierSigner }
|
||||||
|
|
||||||
|
func (s HomesteadSigner) Equal(s2 Signer) bool {
|
||||||
|
_, ok := s2.(HomesteadSigner)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignature returns a new transaction with the given snature.
|
||||||
|
// This snature needs to be formatted as described in the yellow paper (v+27).
|
||||||
|
func (hs HomesteadSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
|
if len(sig) != 65 {
|
||||||
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
}
|
||||||
|
cpy := &Transaction{data: tx.data}
|
||||||
|
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
||||||
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
||||||
|
return cpy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs HomesteadSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
h := hs.Hash(tx)
|
||||||
|
sig, err := crypto.SignEthereum(h[:], prv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return hs.WithSignature(tx, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hs HomesteadSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
|
if tx.data.V.BitLen() > 8 {
|
||||||
|
return nil, ErrInvalidSig
|
||||||
|
}
|
||||||
|
V := byte(tx.data.V.Uint64())
|
||||||
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, true) {
|
||||||
|
return nil, ErrInvalidSig
|
||||||
|
}
|
||||||
|
// encode the snature in uncompressed format
|
||||||
|
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
|
||||||
|
sig := make([]byte, 65)
|
||||||
|
copy(sig[32-len(r):32], r)
|
||||||
|
copy(sig[64-len(s):64], s)
|
||||||
|
sig[64] = V - 27
|
||||||
|
|
||||||
|
// recover the public key from the snature
|
||||||
|
hash := hs.Hash(tx)
|
||||||
|
pub, err := crypto.Ecrecover(hash[:], sig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(pub) == 0 || pub[0] != 4 {
|
||||||
|
return nil, errors.New("invalid public key")
|
||||||
|
}
|
||||||
|
return pub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type FrontierSigner struct{}
|
||||||
|
|
||||||
|
func (s FrontierSigner) Equal(s2 Signer) bool {
|
||||||
|
_, ok := s2.(FrontierSigner)
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithSignature returns a new transaction with the given snature.
|
||||||
|
// This snature needs to be formatted as described in the yellow paper (v+27).
|
||||||
|
func (fs FrontierSigner) WithSignature(tx *Transaction, sig []byte) (*Transaction, error) {
|
||||||
|
if len(sig) != 65 {
|
||||||
|
panic(fmt.Sprintf("wrong size for snature: got %d, want 65", len(sig)))
|
||||||
|
}
|
||||||
|
cpy := &Transaction{data: tx.data}
|
||||||
|
cpy.data.R = new(big.Int).SetBytes(sig[:32])
|
||||||
|
cpy.data.S = new(big.Int).SetBytes(sig[32:64])
|
||||||
|
cpy.data.V = new(big.Int).SetBytes([]byte{sig[64]})
|
||||||
|
return cpy, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs FrontierSigner) SignECDSA(tx *Transaction, prv *ecdsa.PrivateKey) (*Transaction, error) {
|
||||||
|
h := fs.Hash(tx)
|
||||||
|
sig, err := crypto.SignEthereum(h[:], prv)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return fs.WithSignature(tx, sig)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hash returns the hash to be sned by the sender.
|
||||||
|
// It does not uniquely identify the transaction.
|
||||||
|
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
||||||
|
return rlpHash([]interface{}{
|
||||||
|
tx.data.AccountNonce,
|
||||||
|
tx.data.Price,
|
||||||
|
tx.data.GasLimit,
|
||||||
|
tx.data.Recipient,
|
||||||
|
tx.data.Amount,
|
||||||
|
tx.data.Payload,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fs FrontierSigner) PublicKey(tx *Transaction) ([]byte, error) {
|
||||||
|
if tx.data.V.BitLen() > 8 {
|
||||||
|
return nil, ErrInvalidSig
|
||||||
|
}
|
||||||
|
|
||||||
|
V := byte(tx.data.V.Uint64())
|
||||||
|
if !crypto.ValidateSignatureValues(V, tx.data.R, tx.data.S, false) {
|
||||||
|
return nil, ErrInvalidSig
|
||||||
|
}
|
||||||
|
// encode the snature in uncompressed format
|
||||||
|
r, s := tx.data.R.Bytes(), tx.data.S.Bytes()
|
||||||
|
sig := make([]byte, 65)
|
||||||
|
copy(sig[32-len(r):32], r)
|
||||||
|
copy(sig[64-len(s):64], s)
|
||||||
|
sig[64] = V - 27
|
||||||
|
|
||||||
|
// recover the public key from the snature
|
||||||
|
hash := fs.Hash(tx)
|
||||||
|
pub, err := crypto.Ecrecover(hash[:], sig)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(pub) == 0 || pub[0] != 4 {
|
||||||
|
return nil, errors.New("invalid public key")
|
||||||
|
}
|
||||||
|
return pub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// normaliseV returns the Ethereum version of the V parameter
|
||||||
|
func normaliseV(s Signer, v *big.Int) byte {
|
||||||
|
if s, ok := s.(EIP155Signer); ok {
|
||||||
|
stdV := v.BitLen() <= 8 && (v.Uint64() == 27 || v.Uint64() == 28)
|
||||||
|
if s.chainId.BitLen() > 0 && !stdV {
|
||||||
|
nv := byte((new(big.Int).Sub(v, s.chainIdMul).Uint64()) - 35 + 27)
|
||||||
|
return nv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return byte(v.Uint64())
|
||||||
|
}
|
||||||
|
|
||||||
|
// deriveChainId derives the chain id from the given v parameter
|
||||||
|
func deriveChainId(v *big.Int) *big.Int {
|
||||||
|
if v.BitLen() <= 64 {
|
||||||
|
v := v.Uint64()
|
||||||
|
if v == 27 || v == 28 {
|
||||||
|
return new(big.Int)
|
||||||
|
}
|
||||||
|
return new(big.Int).SetUint64((v - 35) / 2)
|
||||||
|
}
|
||||||
|
v = new(big.Int).Sub(v, big.NewInt(35))
|
||||||
|
return v.Div(v, big.NewInt(2))
|
||||||
|
}
|
||||||
138
core/types/transaction_signing_test.go
Normal file
138
core/types/transaction_signing_test.go
Normal file
|
|
@ -0,0 +1,138 @@
|
||||||
|
// Copyright 2016 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 types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEIP155Signing(t *testing.T) {
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
|
signer := NewEIP155Signer(big.NewInt(18))
|
||||||
|
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
from, err := Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if from != addr {
|
||||||
|
t.Errorf("exected from and address to be equal. Got %x want %x", from, addr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEIP155ChainId(t *testing.T) {
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
|
||||||
|
signer := NewEIP155Signer(big.NewInt(18))
|
||||||
|
tx, err := NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil).SignECDSA(signer, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !tx.Protected() {
|
||||||
|
t.Fatal("expected tx to be protected")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.ChainId().Cmp(signer.chainId) != 0 {
|
||||||
|
t.Error("expected chainId to be", signer.chainId, "got", tx.ChainId())
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = NewTransaction(0, addr, new(big.Int), new(big.Int), new(big.Int), nil)
|
||||||
|
tx, err = tx.SignECDSA(HomesteadSigner{}, key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.Protected() {
|
||||||
|
t.Error("didn't expect tx to be protected")
|
||||||
|
}
|
||||||
|
|
||||||
|
if tx.ChainId().BitLen() > 0 {
|
||||||
|
t.Error("expected chain id to be 0 got", tx.ChainId())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEIP155SigningVitalik(t *testing.T) {
|
||||||
|
// Test vectors come from http://vitalik.ca/files/eip155_testvec.txt
|
||||||
|
for i, test := range []struct {
|
||||||
|
txRlp, addr string
|
||||||
|
}{
|
||||||
|
{"f864808504a817c800825208943535353535353535353535353535353535353535808025a0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116da0044852b2a670ade5407e78fb2863c51de9fcb96542a07186fe3aeda6bb8a116d", "0xf0f6f18bca1b28cd68e4357452947e021241e9ce"},
|
||||||
|
{"f864018504a817c80182a410943535353535353535353535353535353535353535018025a0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bcaa0489efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc6", "0x23ef145a395ea3fa3deb533b8a9e1b4c6c25d112"},
|
||||||
|
{"f864028504a817c80282f618943535353535353535353535353535353535353535088025a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5a02d7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5", "0x2e485e0c23b4c3c542628a5f672eeab0ad4888be"},
|
||||||
|
{"f865038504a817c803830148209435353535353535353535353535353535353535351b8025a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4e0a02a80e1ef1d7842f27f2e6be0972bb708b9a135c38860dbe73c27c3486c34f4de", "0x82a88539669a3fd524d669e858935de5e5410cf0"},
|
||||||
|
{"f865048504a817c80483019a28943535353535353535353535353535353535353535408025a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c063a013600b294191fc92924bb3ce4b969c1e7e2bab8f4c93c3fc6d0a51733df3c060", "0xf9358f2538fd5ccfeb848b64a96b743fcc930554"},
|
||||||
|
{"f865058504a817c8058301ec309435353535353535353535353535353535353535357d8025a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1a04eebf77a833b30520287ddd9478ff51abbdffa30aa90a8d655dba0e8a79ce0c1", "0xa8f7aba377317440bc5b26198a363ad22af1f3a4"},
|
||||||
|
{"f866068504a817c80683023e3894353535353535353535353535353535353535353581d88025a06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2fa06455bf8ea6e7463a1046a0b52804526e119b4bf5136279614e0b1e8e296a4e2d", "0xf1f571dc362a0e5b2696b8e775f8491d3e50de35"},
|
||||||
|
{"f867078504a817c807830290409435353535353535353535353535353535353535358201578025a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021a052f1a9b320cab38e5da8a8f97989383aab0a49165fc91c737310e4f7e9821021", "0xd37922162ab7cea97c97a87551ed02c9a38b7332"},
|
||||||
|
{"f867088504a817c8088302e2489435353535353535353535353535353535353535358202008025a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c12a064b1702d9298fee62dfeccc57d322a463ad55ca201256d01f62b45b2e1c21c10", "0x9bddad43f934d313c2b79ca28a432dd2b7281029"},
|
||||||
|
{"f867098504a817c809830334509435353535353535353535353535353535353535358202d98025a052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afba052f8f61201b2b11a78d6e866abc9c3db2ae8631fa656bfe5cb53668255367afb", "0x3c24d7329e92f84f08556ceb6df1cdb0104ca49f"},
|
||||||
|
} {
|
||||||
|
signer := NewEIP155Signer(big.NewInt(1))
|
||||||
|
|
||||||
|
var tx *Transaction
|
||||||
|
err := rlp.DecodeBytes(common.Hex2Bytes(test.txRlp), &tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
from, err := Sender(signer, tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("%d: %v", i, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := common.HexToAddress(test.addr)
|
||||||
|
if from != addr {
|
||||||
|
t.Errorf("%d: expected %x got %x", i, addr, from)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestChainId(t *testing.T) {
|
||||||
|
key, _ := defaultTestKey()
|
||||||
|
|
||||||
|
tx := NewTransaction(0, common.Address{}, new(big.Int), new(big.Int), new(big.Int), nil)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
tx, err = tx.SignECDSA(NewEIP155Signer(big.NewInt(1)), key)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Sender(NewEIP155Signer(big.NewInt(2)), tx)
|
||||||
|
if err != ErrInvalidChainId {
|
||||||
|
t.Error("expected error:", ErrInvalidChainId)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = Sender(NewEIP155Signer(big.NewInt(1)), tx)
|
||||||
|
if err != nil {
|
||||||
|
t.Error("expected no error")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -46,15 +46,16 @@ var (
|
||||||
big.NewInt(1),
|
big.NewInt(1),
|
||||||
common.FromHex("5544"),
|
common.FromHex("5544"),
|
||||||
).WithSignature(
|
).WithSignature(
|
||||||
|
HomesteadSigner{},
|
||||||
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
|
common.Hex2Bytes("98ff921201554726367d2be8c804a7ff89ccf285ebc57dff8ae4c44b9c19ac4a8887321be575c8095f789dd4c743dfe42c1820f9231f98a962b210e3ac2452a31c"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTransactionSigHash(t *testing.T) {
|
func TestTransactionSigHash(t *testing.T) {
|
||||||
if emptyTx.SigHash() != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
|
if emptyTx.SigHash(HomesteadSigner{}) != common.HexToHash("c775b99e7ad12f50d819fcd602390467e28141316969f4b57f0626f74fe3b386") {
|
||||||
t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash())
|
t.Errorf("empty transaction hash mismatch, got %x", emptyTx.Hash())
|
||||||
}
|
}
|
||||||
if rightvrsTx.SigHash() != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
|
if rightvrsTx.SigHash(HomesteadSigner{}) != common.HexToHash("fe7a79529ed5f7c3375d06b26b186a8644e0e16c373d7a12be41c62d6042b77a") {
|
||||||
t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash())
|
t.Errorf("RightVRS transaction hash mismatch, got %x", rightvrsTx.Hash())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -72,7 +73,9 @@ func TestTransactionEncode(t *testing.T) {
|
||||||
|
|
||||||
func decodeTx(data []byte) (*Transaction, error) {
|
func decodeTx(data []byte) (*Transaction, error) {
|
||||||
var tx Transaction
|
var tx Transaction
|
||||||
return &tx, rlp.Decode(bytes.NewReader(data), &tx)
|
t, err := &tx, rlp.Decode(bytes.NewReader(data), &tx)
|
||||||
|
|
||||||
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
|
func defaultTestKey() (*ecdsa.PrivateKey, common.Address) {
|
||||||
|
|
@ -88,7 +91,8 @@ func TestRecipientEmpty(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
from, err := tx.From()
|
|
||||||
|
from, err := Sender(HomesteadSigner{}, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -107,7 +111,7 @@ func TestRecipientNormal(t *testing.T) {
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
from, err := tx.From()
|
from, err := Sender(HomesteadSigner{}, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
|
|
@ -127,12 +131,14 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||||
for i := 0; i < len(keys); i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
keys[i], _ = crypto.GenerateKey()
|
keys[i], _ = crypto.GenerateKey()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := HomesteadSigner{}
|
||||||
// Generate a batch of transactions with overlapping values, but shifted nonces
|
// Generate a batch of transactions with overlapping values, but shifted nonces
|
||||||
groups := map[common.Address]Transactions{}
|
groups := map[common.Address]Transactions{}
|
||||||
for start, key := range keys {
|
for start, key := range keys {
|
||||||
addr := crypto.PubkeyToAddress(key.PublicKey)
|
addr := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
for i := 0; i < 25; i++ {
|
for i := 0; i < 25; i++ {
|
||||||
tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(key)
|
tx, _ := NewTransaction(uint64(start+i), common.Address{}, big.NewInt(100), big.NewInt(100), big.NewInt(int64(start+i)), nil).SignECDSA(signer, key)
|
||||||
groups[addr] = append(groups[addr], tx)
|
groups[addr] = append(groups[addr], tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -148,11 +154,11 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
for i, txi := range txs {
|
for i, txi := range txs {
|
||||||
fromi, _ := txi.From()
|
fromi, _ := Sender(signer, txi)
|
||||||
|
|
||||||
// Make sure the nonce order is valid
|
// Make sure the nonce order is valid
|
||||||
for j, txj := range txs[i+1:] {
|
for j, txj := range txs[i+1:] {
|
||||||
fromj, _ := txj.From()
|
fromj, _ := Sender(signer, txj)
|
||||||
|
|
||||||
if fromi == fromj && txi.Nonce() > txj.Nonce() {
|
if fromi == fromj && txi.Nonce() > txj.Nonce() {
|
||||||
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
|
t.Errorf("invalid nonce ordering: tx #%d (A=%x N=%v) < tx #%d (A=%x N=%v)", i, fromi[:4], txi.Nonce(), i+j, fromj[:4], txj.Nonce())
|
||||||
|
|
@ -161,20 +167,20 @@ func TestTransactionPriceNonceSort(t *testing.T) {
|
||||||
// Find the previous and next nonce of this account
|
// Find the previous and next nonce of this account
|
||||||
prev, next := i-1, i+1
|
prev, next := i-1, i+1
|
||||||
for j := i - 1; j >= 0; j-- {
|
for j := i - 1; j >= 0; j-- {
|
||||||
if fromj, _ := txs[j].From(); fromi == fromj {
|
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
|
||||||
prev = j
|
prev = j
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for j := i + 1; j < len(txs); j++ {
|
for j := i + 1; j < len(txs); j++ {
|
||||||
if fromj, _ := txs[j].From(); fromi == fromj {
|
if fromj, _ := Sender(signer, txs[j]); fromi == fromj {
|
||||||
next = j
|
next = j
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
|
// Make sure that in between the neighbor nonces, the transaction is correctly positioned price wise
|
||||||
for j := prev + 1; j < next; j++ {
|
for j := prev + 1; j < next; j++ {
|
||||||
fromj, _ := txs[j].From()
|
fromj, _ := Sender(signer, txs[j])
|
||||||
if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 {
|
if j < i && txs[j].GasPrice().Cmp(txi.GasPrice()) < 0 {
|
||||||
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
|
t.Errorf("invalid gasprice ordering: tx #%d (A=%x P=%v) < tx #%d (A=%x P=%v)", j, fromj[:4], txs[j].GasPrice(), i, fromi[:4], txi.GasPrice())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RuleSet is an interface that defines the current rule set during the
|
|
||||||
// execution of the EVM instructions (e.g. whether it's homestead)
|
|
||||||
type RuleSet interface {
|
|
||||||
IsHomestead(*big.Int) bool
|
|
||||||
// GasTable returns the gas prices for this phase, which is based on
|
|
||||||
// block number passed in.
|
|
||||||
GasTable(*big.Int) params.GasTable
|
|
||||||
}
|
|
||||||
|
|
||||||
// Environment is an EVM requirement and helper which allows access to outside
|
// Environment is an EVM requirement and helper which allows access to outside
|
||||||
// information such as states.
|
// information such as states.
|
||||||
type Environment interface {
|
type Environment interface {
|
||||||
// The current ruleset
|
// The current ruleset
|
||||||
RuleSet() RuleSet
|
ChainConfig() *params.ChainConfig
|
||||||
// The state database
|
// The state database
|
||||||
Db() Database
|
Db() Database
|
||||||
// Creates a restorable snapshot
|
// Creates a restorable snapshot
|
||||||
|
|
@ -115,6 +106,9 @@ type Database interface {
|
||||||
// Exist reports whether the given account exists in state.
|
// Exist reports whether the given account exists in state.
|
||||||
// Notably this should also return true for suicided accounts.
|
// Notably this should also return true for suicided accounts.
|
||||||
Exist(common.Address) bool
|
Exist(common.Address) bool
|
||||||
|
// Empty returns whether the given account is empty. Empty
|
||||||
|
// is defined according to EIP161 (balance = nonce = code = 0).
|
||||||
|
Empty(common.Address) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account represents a contract or basic ethereum account.
|
// Account represents a contract or basic ethereum account.
|
||||||
|
|
|
||||||
|
|
@ -515,7 +515,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
|
||||||
input = memory.Get(offset.Int64(), size.Int64())
|
input = memory.Get(offset.Int64(), size.Int64())
|
||||||
gas = new(big.Int).Set(contract.Gas)
|
gas = new(big.Int).Set(contract.Gas)
|
||||||
)
|
)
|
||||||
if env.RuleSet().GasTable(env.BlockNumber()).CreateBySuicide != nil {
|
if env.ChainConfig().IsEIP150(env.BlockNumber()) {
|
||||||
gas.Div(gas, n64)
|
gas.Div(gas, n64)
|
||||||
gas = gas.Sub(contract.Gas, gas)
|
gas = gas.Sub(contract.Gas, gas)
|
||||||
}
|
}
|
||||||
|
|
@ -526,7 +526,7 @@ func opCreate(instr instruction, pc *uint64, env Environment, contract *Contract
|
||||||
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
// homestead we must check for CodeStoreOutOfGasError (homestead only
|
||||||
// rule) and treat as an error, if the ruleset is frontier we must
|
// rule) and treat as an error, if the ruleset is frontier we must
|
||||||
// ignore this error and pretend the operation was successful.
|
// ignore this error and pretend the operation was successful.
|
||||||
if env.RuleSet().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
|
if env.ChainConfig().IsHomestead(env.BlockNumber()) && suberr == CodeStoreOutOfGasError {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
} else if suberr != nil && suberr != CodeStoreOutOfGasError {
|
} else if suberr != nil && suberr != CodeStoreOutOfGasError {
|
||||||
stack.push(new(big.Int))
|
stack.push(new(big.Int))
|
||||||
|
|
|
||||||
|
|
@ -319,7 +319,7 @@ func runProgram(program *Program, pcstart uint64, mem *Memory, stack *Stack, env
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
homestead := env.RuleSet().IsHomestead(env.BlockNumber())
|
homestead := env.ChainConfig().IsHomestead(env.BlockNumber())
|
||||||
for pc < uint64(len(program.instructions)) {
|
for pc < uint64(len(program.instructions)) {
|
||||||
instrCount++
|
instrCount++
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
const maxRun = 1000
|
const maxRun = 1000
|
||||||
|
|
@ -172,7 +173,9 @@ func NewEnv(config *Config) *Env {
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) RuleSet() RuleSet { return ruleSet{new(big.Int)} }
|
func (self *Env) ChainConfig() *params.ChainConfig {
|
||||||
|
return params.TestChainConfig
|
||||||
|
}
|
||||||
func (self *Env) Vm() Vm { return self.evm }
|
func (self *Env) Vm() Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return common.Address{} }
|
func (self *Env) Origin() common.Address { return common.Address{} }
|
||||||
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,11 @@
|
||||||
|
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
import "math/big"
|
import (
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
)
|
||||||
|
|
||||||
type jumpPtr struct {
|
type jumpPtr struct {
|
||||||
fn instrFn
|
fn instrFn
|
||||||
|
|
@ -25,7 +29,7 @@ type jumpPtr struct {
|
||||||
|
|
||||||
type vmJumpTable [256]jumpPtr
|
type vmJumpTable [256]jumpPtr
|
||||||
|
|
||||||
func newJumpTable(ruleset RuleSet, blockNumber *big.Int) vmJumpTable {
|
func newJumpTable(ruleset *params.ChainConfig, blockNumber *big.Int) vmJumpTable {
|
||||||
var jumpTable vmJumpTable
|
var jumpTable vmJumpTable
|
||||||
|
|
||||||
// when initialising a new VM execution we must first check the homestead
|
// when initialising a new VM execution we must first check the homestead
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,18 @@ package vm
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInit(t *testing.T) {
|
func TestInit(t *testing.T) {
|
||||||
jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(0))
|
jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(0))
|
||||||
if jumpTable[DELEGATECALL].valid {
|
if jumpTable[DELEGATECALL].valid {
|
||||||
t.Error("Expected DELEGATECALL not to be present")
|
t.Error("Expected DELEGATECALL not to be present")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, n := range []int64{1, 2, 100} {
|
for _, n := range []int64{1, 2, 100} {
|
||||||
jumpTable := newJumpTable(ruleSet{big.NewInt(1)}, big.NewInt(n))
|
jumpTable := newJumpTable(¶ms.ChainConfig{HomesteadBlock: big.NewInt(1)}, big.NewInt(n))
|
||||||
if !jumpTable[DELEGATECALL].valid {
|
if !jumpTable[DELEGATECALL].valid {
|
||||||
t.Error("Expected DELEGATECALL to be present for block", n)
|
t.Error("Expected DELEGATECALL to be present for block", n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,14 @@ import (
|
||||||
"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/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Env is a basic runtime environment required for running the EVM.
|
// Env is a basic runtime environment required for running the EVM.
|
||||||
type Env struct {
|
type Env struct {
|
||||||
ruleSet vm.RuleSet
|
chainConfig *params.ChainConfig
|
||||||
depth int
|
depth int
|
||||||
state *state.StateDB
|
state *state.StateDB
|
||||||
|
|
||||||
origin common.Address
|
origin common.Address
|
||||||
coinbase common.Address
|
coinbase common.Address
|
||||||
|
|
@ -47,14 +48,14 @@ type Env struct {
|
||||||
// NewEnv returns a new vm.Environment
|
// NewEnv returns a new vm.Environment
|
||||||
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
||||||
env := &Env{
|
env := &Env{
|
||||||
ruleSet: cfg.RuleSet,
|
chainConfig: cfg.ChainConfig,
|
||||||
state: state,
|
state: state,
|
||||||
origin: cfg.Origin,
|
origin: cfg.Origin,
|
||||||
coinbase: cfg.Coinbase,
|
coinbase: cfg.Coinbase,
|
||||||
number: cfg.BlockNumber,
|
number: cfg.BlockNumber,
|
||||||
time: cfg.Time,
|
time: cfg.Time,
|
||||||
difficulty: cfg.Difficulty,
|
difficulty: cfg.Difficulty,
|
||||||
gasLimit: cfg.GasLimit,
|
gasLimit: cfg.GasLimit,
|
||||||
}
|
}
|
||||||
env.evm = vm.New(env, vm.Config{
|
env.evm = vm.New(env, vm.Config{
|
||||||
Debug: cfg.Debug,
|
Debug: cfg.Debug,
|
||||||
|
|
@ -65,16 +66,16 @@ func NewEnv(cfg *Config, state *state.StateDB) vm.Environment {
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) RuleSet() vm.RuleSet { return self.ruleSet }
|
func (self *Env) ChainConfig() *params.ChainConfig { return self.chainConfig }
|
||||||
func (self *Env) Vm() vm.Vm { return self.evm }
|
func (self *Env) Vm() vm.Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return self.origin }
|
func (self *Env) Origin() common.Address { return self.origin }
|
||||||
func (self *Env) BlockNumber() *big.Int { return self.number }
|
func (self *Env) BlockNumber() *big.Int { return self.number }
|
||||||
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
func (self *Env) Coinbase() common.Address { return self.coinbase }
|
||||||
func (self *Env) Time() *big.Int { return self.time }
|
func (self *Env) Time() *big.Int { return self.time }
|
||||||
func (self *Env) Difficulty() *big.Int { return self.difficulty }
|
func (self *Env) Difficulty() *big.Int { return self.difficulty }
|
||||||
func (self *Env) Db() vm.Database { return self.state }
|
func (self *Env) Db() vm.Database { return self.state }
|
||||||
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
|
func (self *Env) GasLimit() *big.Int { return self.gasLimit }
|
||||||
func (self *Env) VmType() vm.Type { return vm.StdVmTy }
|
func (self *Env) VmType() vm.Type { return vm.StdVmTy }
|
||||||
func (self *Env) GetHash(n uint64) common.Hash {
|
func (self *Env) GetHash(n uint64) common.Hash {
|
||||||
return self.getHashFn(n)
|
return self.getHashFn(n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -39,7 +38,7 @@ func (ruleSet) GasTable(*big.Int) params.GasTable {
|
||||||
// Config is a basic type specifying certain configuration flags for running
|
// Config is a basic type specifying certain configuration flags for running
|
||||||
// the EVM.
|
// the EVM.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
RuleSet vm.RuleSet
|
ChainConfig *params.ChainConfig
|
||||||
Difficulty *big.Int
|
Difficulty *big.Int
|
||||||
Origin common.Address
|
Origin common.Address
|
||||||
Coinbase common.Address
|
Coinbase common.Address
|
||||||
|
|
@ -57,8 +56,16 @@ type Config struct {
|
||||||
|
|
||||||
// sets defaults on the config
|
// sets defaults on the config
|
||||||
func setDefaults(cfg *Config) {
|
func setDefaults(cfg *Config) {
|
||||||
if cfg.RuleSet == nil {
|
if cfg.ChainConfig == nil {
|
||||||
cfg.RuleSet = ruleSet{}
|
cfg.ChainConfig = ¶ms.ChainConfig{
|
||||||
|
ChainId: big.NewInt(1),
|
||||||
|
HomesteadBlock: new(big.Int),
|
||||||
|
DAOForkBlock: new(big.Int),
|
||||||
|
DAOForkSupport: false,
|
||||||
|
EIP150Block: new(big.Int),
|
||||||
|
EIP155Block: new(big.Int),
|
||||||
|
EIP158Block: new(big.Int),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Difficulty == nil {
|
if cfg.Difficulty == nil {
|
||||||
|
|
|
||||||
|
|
@ -51,9 +51,9 @@ type EVM struct {
|
||||||
func New(env Environment, cfg Config) *EVM {
|
func New(env Environment, cfg Config) *EVM {
|
||||||
return &EVM{
|
return &EVM{
|
||||||
env: env,
|
env: env,
|
||||||
jumpTable: newJumpTable(env.RuleSet(), env.BlockNumber()),
|
jumpTable: newJumpTable(env.ChainConfig(), env.BlockNumber()),
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
gasTable: env.RuleSet().GasTable(env.BlockNumber()),
|
gasTable: env.ChainConfig().GasTable(env.BlockNumber()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -172,6 +172,7 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
|
|
||||||
// Get the memory location of pc
|
// Get the memory location of pc
|
||||||
op = contract.GetOp(pc)
|
op = contract.GetOp(pc)
|
||||||
|
//fmt.Printf("OP %d %v\n", op, op)
|
||||||
// calculate the new memory size and gas price for the current executing opcode
|
// calculate the new memory size and gas price for the current executing opcode
|
||||||
newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
|
newMemSize, cost, err = calculateGasAndSize(evm.gasTable, evm.env, contract, caller, op, statedb, mem, stack)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -254,10 +255,20 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
|
||||||
// stack Check, memory resize & gas phase
|
// stack Check, memory resize & gas phase
|
||||||
switch op {
|
switch op {
|
||||||
case SUICIDE:
|
case SUICIDE:
|
||||||
// if suicide is not nil: homestead gas fork
|
// EIP150 homestead gas reprice fork:
|
||||||
if gasTable.CreateBySuicide != nil {
|
if gasTable.CreateBySuicide != nil {
|
||||||
gas.Set(gasTable.Suicide)
|
gas.Set(gasTable.Suicide)
|
||||||
if !env.Db().Exist(common.BigToAddress(stack.data[len(stack.data)-1])) {
|
var (
|
||||||
|
address = common.BigToAddress(stack.data[len(stack.data)-1])
|
||||||
|
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber())
|
||||||
|
)
|
||||||
|
|
||||||
|
if eip158 {
|
||||||
|
// if empty and transfers value
|
||||||
|
if env.Db().Empty(address) && statedb.GetBalance(contract.Address()).BitLen() > 0 {
|
||||||
|
gas.Add(gas, gasTable.CreateBySuicide)
|
||||||
|
}
|
||||||
|
} else if !env.Db().Exist(address) {
|
||||||
gas.Add(gas, gasTable.CreateBySuicide)
|
gas.Add(gas, gasTable.CreateBySuicide)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -302,7 +313,8 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
|
||||||
|
|
||||||
quadMemGas(mem, newMemSize, gas)
|
quadMemGas(mem, newMemSize, gas)
|
||||||
case EXP:
|
case EXP:
|
||||||
gas.Add(gas, new(big.Int).Mul(big.NewInt(int64(len(stack.data[stack.len()-2].Bytes()))), params.ExpByteGas))
|
expByteLen := int64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
||||||
|
gas.Add(gas, new(big.Int).Mul(big.NewInt(expByteLen), gasTable.ExpByte))
|
||||||
case SSTORE:
|
case SSTORE:
|
||||||
err := stack.require(2)
|
err := stack.require(2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -378,12 +390,21 @@ func calculateGasAndSize(gasTable params.GasTable, env Environment, contract *Co
|
||||||
case CALL, CALLCODE:
|
case CALL, CALLCODE:
|
||||||
gas.Set(gasTable.Calls)
|
gas.Set(gasTable.Calls)
|
||||||
|
|
||||||
|
transfersValue := stack.data[len(stack.data)-3].BitLen() > 0
|
||||||
if op == CALL {
|
if op == CALL {
|
||||||
if !env.Db().Exist(common.BigToAddress(stack.data[stack.len()-2])) {
|
var (
|
||||||
|
address = common.BigToAddress(stack.data[len(stack.data)-2])
|
||||||
|
eip158 = env.ChainConfig().IsEIP158(env.BlockNumber())
|
||||||
|
)
|
||||||
|
if eip158 {
|
||||||
|
if env.Db().Empty(address) && transfersValue {
|
||||||
|
gas.Add(gas, params.CallNewAccountGas)
|
||||||
|
}
|
||||||
|
} else if !env.Db().Exist(address) {
|
||||||
gas.Add(gas, params.CallNewAccountGas)
|
gas.Add(gas, params.CallNewAccountGas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(stack.data[stack.len()-3].Bytes()) > 0 {
|
if transfersValue {
|
||||||
gas.Add(gas, params.CallValueTransferGas)
|
gas.Add(gas, params.CallValueTransferGas)
|
||||||
}
|
}
|
||||||
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
|
x := calcMemSize(stack.data[stack.len()-6], stack.data[stack.len()-7])
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetHashFn returns a function for which the VM env can query block hashes through
|
// GetHashFn returns a function for which the VM env can query block hashes through
|
||||||
|
|
@ -41,18 +42,18 @@ func GetHashFn(ref common.Hash, chain *BlockChain) func(n uint64) common.Hash {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VMEnv struct {
|
type VMEnv struct {
|
||||||
chainConfig *ChainConfig // Chain configuration
|
chainConfig *params.ChainConfig // Chain configuration
|
||||||
state *state.StateDB // State to use for executing
|
state *state.StateDB // State to use for executing
|
||||||
evm *vm.EVM // The Ethereum Virtual Machine
|
evm *vm.EVM // The Ethereum Virtual Machine
|
||||||
depth int // Current execution depth
|
depth int // Current execution depth
|
||||||
msg Message // Message appliod
|
msg Message // Message appliod
|
||||||
|
|
||||||
header *types.Header // Header information
|
header *types.Header // Header information
|
||||||
chain *BlockChain // Blockchain handle
|
chain *BlockChain // Blockchain handle
|
||||||
getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes
|
getHashFn func(uint64) common.Hash // getHashFn callback is used to retrieve block hashes
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
func NewEnv(state *state.StateDB, chainConfig *params.ChainConfig, chain *BlockChain, msg Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||||
env := &VMEnv{
|
env := &VMEnv{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
|
|
@ -66,18 +67,18 @@ func NewEnv(state *state.StateDB, chainConfig *ChainConfig, chain *BlockChain, m
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
|
func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
|
func (self *VMEnv) Origin() common.Address { return self.msg.From() }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
||||||
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
||||||
func (self *VMEnv) Time() *big.Int { return self.header.Time }
|
func (self *VMEnv) Time() *big.Int { return self.header.Time }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
|
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
|
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
|
||||||
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
func (self *VMEnv) Value() *big.Int { return self.msg.Value() }
|
||||||
func (self *VMEnv) Db() vm.Database { return self.state }
|
func (self *VMEnv) Db() vm.Database { return self.state }
|
||||||
func (self *VMEnv) Depth() int { return self.depth }
|
func (self *VMEnv) Depth() int { return self.depth }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
||||||
return self.getHashFn(n)
|
return self.getHashFn(n)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
17
eth/api.go
17
eth/api.go
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
@ -303,13 +304,13 @@ func (api *PublicDebugAPI) DumpBlock(number uint64) (state.Dump, error) {
|
||||||
// PrivateDebugAPI is the collection of Etheruem full node APIs exposed over
|
// PrivateDebugAPI is the collection of Etheruem full node APIs exposed over
|
||||||
// the private debugging endpoint.
|
// the private debugging endpoint.
|
||||||
type PrivateDebugAPI struct {
|
type PrivateDebugAPI struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
eth *Ethereum
|
eth *Ethereum
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrivateDebugAPI creates a new API definition for the full node-related
|
// NewPrivateDebugAPI creates a new API definition for the full node-related
|
||||||
// private debug methods of the Ethereum service.
|
// private debug methods of the Ethereum service.
|
||||||
func NewPrivateDebugAPI(config *core.ChainConfig, eth *Ethereum) *PrivateDebugAPI {
|
func NewPrivateDebugAPI(config *params.ChainConfig, eth *Ethereum) *PrivateDebugAPI {
|
||||||
return &PrivateDebugAPI{config: config, eth: eth}
|
return &PrivateDebugAPI{config: config, eth: eth}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,21 +506,15 @@ func (api *PrivateDebugAPI) TraceTransaction(ctx context.Context, txHash common.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := types.MakeSigner(api.config, block.Number())
|
||||||
// Mutate the state and trace the selected transaction
|
// Mutate the state and trace the selected transaction
|
||||||
for idx, tx := range block.Transactions() {
|
for idx, tx := range block.Transactions() {
|
||||||
// Assemble the transaction call message
|
// Assemble the transaction call message
|
||||||
from, err := tx.FromFrontier()
|
msg, err := tx.AsMessage(signer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("sender retrieval failed: %v", err)
|
return nil, fmt.Errorf("sender retrieval failed: %v", err)
|
||||||
}
|
}
|
||||||
msg := callmsg{
|
|
||||||
addr: from,
|
|
||||||
to: tx.To(),
|
|
||||||
gas: tx.Gas(),
|
|
||||||
gasPrice: tx.GasPrice(),
|
|
||||||
value: tx.Value(),
|
|
||||||
data: tx.Data(),
|
|
||||||
}
|
|
||||||
// Mutate the state if we haven't reached the tracing transaction yet
|
// Mutate the state if we haven't reached the tracing transaction yet
|
||||||
if uint64(idx) < txIndex {
|
if uint64(idx) < txIndex {
|
||||||
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})
|
vmenv := core.NewEnv(stateDb, api.config, api.eth.BlockChain(), msg, block.Header(), vm.Config{})
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
@ -40,6 +41,14 @@ type EthApiBackend struct {
|
||||||
gpo *gasprice.GasPriceOracle
|
gpo *gasprice.GasPriceOracle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) ChainConfig() *params.ChainConfig {
|
||||||
|
return b.eth.chainConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthApiBackend) CurrentBlock() *types.Block {
|
||||||
|
return b.eth.blockchain.CurrentBlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (b *EthApiBackend) SetHead(number uint64) {
|
func (b *EthApiBackend) SetHead(number uint64) {
|
||||||
b.eth.blockchain.SetHead(number)
|
b.eth.blockchain.SetHead(number)
|
||||||
}
|
}
|
||||||
|
|
@ -99,11 +108,10 @@ func (b *EthApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
|
|
||||||
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
func (b *EthApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
||||||
statedb := state.(EthApiState).state
|
statedb := state.(EthApiState).state
|
||||||
addr, _ := msg.From()
|
from := statedb.GetOrNewStateObject(msg.From())
|
||||||
from := statedb.GetOrNewStateObject(addr)
|
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
vmError := func() error { return nil }
|
vmError := func() error { return nil }
|
||||||
return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig), vmError, nil
|
return core.NewEnv(statedb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{}), vmError, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
func (b *EthApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/registrar/ethreg"
|
"github.com/ethereum/go-ethereum/common/registrar/ethreg"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"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/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -47,6 +46,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
ChainConfig *core.ChainConfig // chain configuration
|
ChainConfig *params.ChainConfig // chain configuration
|
||||||
|
|
||||||
NetworkId int // Network ID to use for selecting peers to connect to
|
NetworkId int // Network ID to use for selecting peers to connect to
|
||||||
Genesis string // Genesis JSON to seed the chain database with
|
Genesis string // Genesis JSON to seed the chain database with
|
||||||
|
|
@ -112,7 +112,7 @@ type LesServer interface {
|
||||||
|
|
||||||
// Ethereum implements the Ethereum full node service.
|
// Ethereum implements the Ethereum full node service.
|
||||||
type Ethereum struct {
|
type Ethereum struct {
|
||||||
chainConfig *core.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
// Channel for shutting down the service
|
// Channel for shutting down the service
|
||||||
shutdownChan chan bool // Channel for shutting down the ethereum
|
shutdownChan chan bool // Channel for shutting down the ethereum
|
||||||
stopDbUpgrade func() // stop chain db sequential key upgrade
|
stopDbUpgrade func() // stop chain db sequential key upgrade
|
||||||
|
|
@ -217,10 +217,6 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
|
||||||
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
|
core.WriteChainConfig(chainDb, genesis.Hash(), config.ChainConfig)
|
||||||
|
|
||||||
eth.chainConfig = config.ChainConfig
|
eth.chainConfig = config.ChainConfig
|
||||||
eth.chainConfig.VmConfig = vm.Config{
|
|
||||||
EnableJit: config.EnableJit,
|
|
||||||
ForceJit: config.ForceJit,
|
|
||||||
}
|
|
||||||
|
|
||||||
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
|
eth.blockchain, err = core.NewBlockChain(chainDb, eth.chainConfig, eth.pow, eth.EventMux())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"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/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMipmapUpgrade(t *testing.T) {
|
func TestMipmapUpgrade(t *testing.T) {
|
||||||
|
|
@ -32,7 +33,7 @@ func TestMipmapUpgrade(t *testing.T) {
|
||||||
addr := common.BytesToAddress([]byte("jeff"))
|
addr := common.BytesToAddress([]byte("jeff"))
|
||||||
genesis := core.WriteGenesisBlockForTesting(db)
|
genesis := core.WriteGenesisBlockForTesting(db)
|
||||||
|
|
||||||
chain, receipts := core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ func newTester() *downloadTester {
|
||||||
// reassembly.
|
// reassembly.
|
||||||
func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) {
|
func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Receipts, heavy bool) ([]common.Hash, map[common.Hash]*types.Header, map[common.Hash]*types.Block, map[common.Hash]types.Receipts) {
|
||||||
// Generate the block chain
|
// Generate the block chain
|
||||||
blocks, receipts := core.GenerateChain(nil, parent, dl.peerDb, n, func(i int, block *core.BlockGen) {
|
blocks, receipts := core.GenerateChain(params.TestChainConfig, parent, dl.peerDb, n, func(i int, block *core.BlockGen) {
|
||||||
block.SetCoinbase(common.Address{seed})
|
block.SetCoinbase(common.Address{seed})
|
||||||
|
|
||||||
// If a heavy chain is requested, delay blocks to raise difficulty
|
// If a heavy chain is requested, delay blocks to raise difficulty
|
||||||
|
|
@ -118,7 +118,8 @@ func (dl *downloadTester) makeChain(n int, seed byte, parent *types.Block, paren
|
||||||
}
|
}
|
||||||
// If the block number is multiple of 3, send a bonus transaction to the miner
|
// If the block number is multiple of 3, send a bonus transaction to the miner
|
||||||
if parent == dl.genesis && i%3 == 0 {
|
if parent == dl.genesis && i%3 == 0 {
|
||||||
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey)
|
signer := types.MakeSigner(params.TestChainConfig, block.Number())
|
||||||
|
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,13 @@ var (
|
||||||
// contains a transaction and every 5th an uncle to allow testing correct block
|
// contains a transaction and every 5th an uncle to allow testing correct block
|
||||||
// reassembly.
|
// reassembly.
|
||||||
func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
|
func makeChain(n int, seed byte, parent *types.Block) ([]common.Hash, map[common.Hash]*types.Block) {
|
||||||
blocks, _ := core.GenerateChain(nil, parent, testdb, n, func(i int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(params.TestChainConfig, parent, testdb, n, func(i int, block *core.BlockGen) {
|
||||||
block.SetCoinbase(common.Address{seed})
|
block.SetCoinbase(common.Address{seed})
|
||||||
|
|
||||||
// If the block number is multiple of 3, send a bonus transaction to the miner
|
// If the block number is multiple of 3, send a bonus transaction to the miner
|
||||||
if parent == genesis && i%3 == 0 {
|
if parent == genesis && i%3 == 0 {
|
||||||
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testKey)
|
signer := types.MakeSigner(params.TestChainConfig, block.Number())
|
||||||
|
tx, err := types.NewTransaction(block.TxNonce(testAddress), common.Address{seed}, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -81,7 +82,7 @@ func TestBlockSubscription(t *testing.T) {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
genesis = core.WriteGenesisBlockForTesting(db)
|
genesis = core.WriteGenesisBlockForTesting(db)
|
||||||
chain, _ = core.GenerateChain(nil, genesis, db, 10, func(i int, gen *core.BlockGen) {})
|
chain, _ = core.GenerateChain(params.TestChainConfig, genesis, db, 10, func(i int, gen *core.BlockGen) {})
|
||||||
chainEvents = []core.ChainEvent{}
|
chainEvents = []core.ChainEvent{}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeReceipt(addr common.Address) *types.Receipt {
|
func makeReceipt(addr common.Address) *types.Receipt {
|
||||||
|
|
@ -60,7 +61,7 @@ func BenchmarkMipmaps(b *testing.B) {
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
|
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr1, Balance: big.NewInt(1000000)})
|
||||||
chain, receipts := core.GenerateChain(nil, genesis, db, 100010, func(i int, gen *core.BlockGen) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 100010, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 2403:
|
case 2403:
|
||||||
|
|
@ -137,7 +138,7 @@ func TestFilters(t *testing.T) {
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
|
genesis := core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: addr, Balance: big.NewInt(1000000)})
|
||||||
chain, receipts := core.GenerateChain(nil, genesis, db, 1000, func(i int, gen *core.BlockGen) {
|
chain, receipts := core.GenerateChain(params.TestChainConfig, genesis, db, 1000, func(i int, gen *core.BlockGen) {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
switch i {
|
switch i {
|
||||||
case 1:
|
case 1:
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
@ -67,7 +68,7 @@ type ProtocolManager struct {
|
||||||
txpool txPool
|
txpool txPool
|
||||||
blockchain *core.BlockChain
|
blockchain *core.BlockChain
|
||||||
chaindb ethdb.Database
|
chaindb ethdb.Database
|
||||||
chainconfig *core.ChainConfig
|
chainconfig *params.ChainConfig
|
||||||
maxPeers int
|
maxPeers int
|
||||||
|
|
||||||
downloader *downloader.Downloader
|
downloader *downloader.Downloader
|
||||||
|
|
@ -95,7 +96,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 *core.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*ProtocolManager, error) {
|
func NewProtocolManager(config *params.ChainConfig, fastSync bool, networkId int, maxPeers int, mux *event.TypeMux, txpool txPool, pow pow.PoW, blockchain *core.BlockChain, chaindb ethdb.Database) (*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,
|
||||||
|
|
|
||||||
|
|
@ -305,18 +305,19 @@ func testGetNodeData(t *testing.T, protocol int) {
|
||||||
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
|
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
|
||||||
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
|
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
|
||||||
|
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
|
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
|
||||||
generator := func(i int, block *core.BlockGen) {
|
generator := func(i int, block *core.BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// In block 1, the test bank sends account #1 some ether.
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// acc1Addr passes it on to account #2.
|
||||||
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
|
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -396,18 +397,19 @@ func testGetReceipt(t *testing.T, protocol int) {
|
||||||
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
|
acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey)
|
||||||
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
|
acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey)
|
||||||
|
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
|
// Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_markets_test)
|
||||||
generator := func(i int, block *core.BlockGen) {
|
generator := func(i int, block *core.BlockGen) {
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// In block 1, the test bank sends account #1 some ether.
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// acc1Addr passes it on to account #2.
|
||||||
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx1, _ := types.NewTransaction(block.TxNonce(testBank.Address), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
|
tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
case 2:
|
case 2:
|
||||||
|
|
@ -466,7 +468,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||||
pow = new(core.FakePow)
|
pow = new(core.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db)
|
genesis = core.WriteGenesisBlockForTesting(db)
|
||||||
config = &core.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked}
|
||||||
blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
|
blockchain, _ = core.NewBlockChain(db, config, pow, evmux)
|
||||||
)
|
)
|
||||||
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
|
pm, err := NewProtocolManager(config, false, NetworkId, 1000, evmux, new(testTxPool), pow, blockchain, db)
|
||||||
|
|
@ -491,7 +493,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool
|
||||||
}
|
}
|
||||||
// Create a block to reply to the challenge if no timeout is simualted
|
// Create a block to reply to the challenge if no timeout is simualted
|
||||||
if !timeout {
|
if !timeout {
|
||||||
blocks, _ := core.GenerateChain(nil, genesis, db, 1, func(i int, block *core.BlockGen) {
|
blocks, _ := core.GenerateChain(¶ms.ChainConfig{}, genesis, db, 1, func(i int, block *core.BlockGen) {
|
||||||
if remoteForked {
|
if remoteForked {
|
||||||
block.SetExtra(params.DAOForkBlockExtra)
|
block.SetExtra(params.DAOForkBlockExtra)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -54,10 +55,10 @@ func newTestProtocolManager(fastSync bool, blocks int, generator func(int, *core
|
||||||
pow = new(core.FakePow)
|
pow = new(core.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db, testBank)
|
genesis = core.WriteGenesisBlockForTesting(db, testBank)
|
||||||
chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
||||||
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
|
blockchain, _ = core.NewBlockChain(db, chainConfig, pow, evmux)
|
||||||
)
|
)
|
||||||
chain, _ := core.GenerateChain(nil, genesis, db, blocks, generator)
|
chain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(chain); err != nil {
|
if _, err := blockchain.InsertChain(chain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -109,7 +110,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
|
||||||
|
|
||||||
batches := make(map[common.Address]types.Transactions)
|
batches := make(map[common.Address]types.Transactions)
|
||||||
for _, tx := range p.pool {
|
for _, tx := range p.pool {
|
||||||
from, _ := tx.From()
|
from, _ := types.Sender(types.HomesteadSigner{}, tx)
|
||||||
batches[from] = append(batches[from], tx)
|
batches[from] = append(batches[from], tx)
|
||||||
}
|
}
|
||||||
for _, batch := range batches {
|
for _, batch := range batches {
|
||||||
|
|
@ -121,7 +122,7 @@ func (p *testTxPool) Pending() map[common.Address]types.Transactions {
|
||||||
// newTestTransaction create a new dummy transaction.
|
// newTestTransaction create a new dummy transaction.
|
||||||
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
|
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
|
||||||
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
|
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
|
||||||
tx, _ = tx.SignECDSA(from)
|
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,7 @@ func (ec *Client) TransactionByHash(ctx context.Context, hash common.Hash) (*typ
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByHash", hash)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if _, r, _ := tx.SignatureValues(); r == nil {
|
if _, r, _ := tx.RawSignatureValues(); r == nil {
|
||||||
return nil, fmt.Errorf("server returned transaction without signature")
|
return nil, fmt.Errorf("server returned transaction without signature")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -166,7 +166,11 @@ func (ec *Client) TransactionInBlock(ctx context.Context, blockHash common.Hash,
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index)
|
err := ec.c.CallContext(ctx, &tx, "eth_getTransactionByBlockHashAndIndex", blockHash, index)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if _, r, _ := tx.SignatureValues(); r == nil {
|
var signer types.Signer = types.HomesteadSigner{}
|
||||||
|
if tx.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
|
}
|
||||||
|
if _, r, _ := types.SignatureValues(signer, tx); r == nil {
|
||||||
return nil, fmt.Errorf("server returned transaction without signature")
|
return nil, fmt.Errorf("server returned transaction without signature")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ func GOPATH() string {
|
||||||
if len(path) == 0 {
|
if len(path) == 0 {
|
||||||
log.Fatal("GOPATH is not set")
|
log.Fatal("GOPATH is not set")
|
||||||
}
|
}
|
||||||
// Ensure that our internal vendor folder in on GOPATH
|
// Ensure that our internal vendor folder is on GOPATH
|
||||||
vendor, _ := filepath.Abs(filepath.Join("build", "_vendor"))
|
vendor, _ := filepath.Abs(filepath.Join("build", "_vendor"))
|
||||||
for _, dir := range path {
|
for _, dir := range path {
|
||||||
if dir == vendor {
|
if dir == vendor {
|
||||||
|
|
|
||||||
|
|
@ -279,7 +279,8 @@ func (s *PrivateAccountAPI) SendTransaction(ctx context.Context, args SendTxArgs
|
||||||
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
|
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
signature, err := s.am.SignWithPassphrase(args.From, passwd, tx.SigHash().Bytes())
|
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
|
||||||
|
signature, err := s.am.SignWithPassphrase(args.From, passwd, signer.Hash(tx).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -537,22 +538,14 @@ func (s *PublicBlockChainAPI) doCall(ctx context.Context, args CallArgs, blockNr
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assemble the CALL invocation
|
// Assemble the CALL invocation
|
||||||
msg := callmsg{
|
gas, gasPrice := args.Gas.BigInt(), args.GasPrice.BigInt()
|
||||||
addr: addr,
|
if gas.Cmp(common.Big0) == 0 {
|
||||||
to: args.To,
|
gas = big.NewInt(50000000)
|
||||||
gas: args.Gas.BigInt(),
|
|
||||||
gasPrice: args.GasPrice.BigInt(),
|
|
||||||
value: args.Value.BigInt(),
|
|
||||||
data: common.FromHex(args.Data),
|
|
||||||
}
|
}
|
||||||
|
if gasPrice.Cmp(common.Big0) == 0 {
|
||||||
if msg.gas.Cmp(common.Big0) == 0 {
|
gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
||||||
msg.gas = big.NewInt(50000000)
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.gasPrice.Cmp(common.Big0) == 0 {
|
|
||||||
msg.gasPrice = new(big.Int).Mul(big.NewInt(50), common.Shannon)
|
|
||||||
}
|
}
|
||||||
|
msg := types.NewMessage(addr, args.To, 0, args.Value.BigInt(), gas, gasPrice, common.FromHex(args.Data), false)
|
||||||
|
|
||||||
// Execute the call and return
|
// Execute the call and return
|
||||||
vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
|
vmenv, vmError, err := s.b.GetVMEnv(ctx, msg, state, header)
|
||||||
|
|
@ -714,8 +707,12 @@ type RPCTransaction struct {
|
||||||
|
|
||||||
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
|
||||||
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
||||||
from, _ := tx.FromFrontier()
|
var signer types.Signer = types.FrontierSigner{}
|
||||||
v, r, s := tx.SignatureValues()
|
if tx.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
|
}
|
||||||
|
from, _ := types.Sender(signer, tx)
|
||||||
|
v, r, s := types.SignatureValues(signer, tx)
|
||||||
return &RPCTransaction{
|
return &RPCTransaction{
|
||||||
From: from,
|
From: from,
|
||||||
Gas: rpc.NewHexNumber(tx.Gas()),
|
Gas: rpc.NewHexNumber(tx.Gas()),
|
||||||
|
|
@ -735,11 +732,12 @@ func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
|
||||||
func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) {
|
func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransaction, error) {
|
||||||
if txIndex >= 0 && txIndex < len(b.Transactions()) {
|
if txIndex >= 0 && txIndex < len(b.Transactions()) {
|
||||||
tx := b.Transactions()[txIndex]
|
tx := b.Transactions()[txIndex]
|
||||||
from, err := tx.FromFrontier()
|
var signer types.Signer = types.FrontierSigner{}
|
||||||
if err != nil {
|
if tx.Protected() {
|
||||||
return nil, err
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
}
|
}
|
||||||
v, r, s := tx.SignatureValues()
|
from, _ := types.Sender(signer, tx)
|
||||||
|
v, r, s := tx.RawSignatureValues()
|
||||||
return &RPCTransaction{
|
return &RPCTransaction{
|
||||||
BlockHash: b.Hash(),
|
BlockHash: b.Hash(),
|
||||||
BlockNumber: rpc.NewHexNumber(b.Number()),
|
BlockNumber: rpc.NewHexNumber(b.Number()),
|
||||||
|
|
@ -958,11 +956,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
from, err := tx.FromFrontier()
|
var signer types.Signer = types.FrontierSigner{}
|
||||||
if err != nil {
|
if tx.Protected() {
|
||||||
glog.V(logger.Debug).Infof("%v\n", err)
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
return nil, nil
|
|
||||||
}
|
}
|
||||||
|
from, _ := types.Sender(signer, tx)
|
||||||
|
|
||||||
fields := map[string]interface{}{
|
fields := map[string]interface{}{
|
||||||
"root": rpc.HexBytes(receipt.PostState),
|
"root": rpc.HexBytes(receipt.PostState),
|
||||||
|
|
@ -990,11 +988,13 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
|
||||||
|
|
||||||
// sign is a helper function that signs a transaction with the private key of the given address.
|
// sign is a helper function that signs a transaction with the private key of the given address.
|
||||||
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
signature, err := s.b.AccountManager().SignEthereum(addr, tx.SigHash().Bytes())
|
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
|
||||||
|
|
||||||
|
signature, err := s.b.AccountManager().SignEthereum(addr, signer.Hash(tx).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return tx.WithSignature(signature)
|
return tx.WithSignature(signer, signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
|
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
|
||||||
|
|
@ -1028,7 +1028,9 @@ func prepareSendTxArgs(ctx context.Context, args SendTxArgs, b Backend) (SendTxA
|
||||||
|
|
||||||
// submitTransaction is a helper function that submits tx to txPool and creates a log entry.
|
// submitTransaction is a helper function that submits tx to txPool and creates a log entry.
|
||||||
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) {
|
func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, signature []byte) (common.Hash, error) {
|
||||||
signedTx, err := tx.WithSignature(signature)
|
signer := types.MakeSigner(b.ChainConfig(), b.CurrentBlock().Number())
|
||||||
|
|
||||||
|
signedTx, err := tx.WithSignature(signer, signature)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1038,7 +1040,7 @@ func submitTransaction(ctx context.Context, b Backend, tx *types.Transaction, si
|
||||||
}
|
}
|
||||||
|
|
||||||
if signedTx.To() == nil {
|
if signedTx.To() == nil {
|
||||||
from, _ := signedTx.From()
|
from, _ := types.Sender(signer, signedTx)
|
||||||
addr := crypto.CreateAddress(from, signedTx.Nonce())
|
addr := crypto.CreateAddress(from, signedTx.Nonce())
|
||||||
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
|
glog.V(logger.Info).Infof("Tx(%s) created: %s\n", signedTx.Hash().Hex(), addr.Hex())
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1072,7 +1074,8 @@ func (s *PublicTransactionPoolAPI) SendTransaction(ctx context.Context, args Sen
|
||||||
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
|
tx = types.NewTransaction(args.Nonce.Uint64(), *args.To, args.Value.BigInt(), args.Gas.BigInt(), args.GasPrice.BigInt(), common.FromHex(args.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
signature, err := s.b.AccountManager().SignEthereum(args.From, tx.SigHash().Bytes())
|
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
|
||||||
|
signature, err := s.b.AccountManager().SignEthereum(args.From, signer.Hash(tx).Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -1092,8 +1095,9 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
|
||||||
if tx.To() == nil {
|
if tx.To() == nil {
|
||||||
from, err := tx.FromFrontier()
|
from, err := types.Sender(signer, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
@ -1202,7 +1206,12 @@ type SignTransactionResult struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTx(t *types.Transaction) *Tx {
|
func newTx(t *types.Transaction) *Tx {
|
||||||
from, _ := t.FromFrontier()
|
var signer types.Signer = types.HomesteadSigner{}
|
||||||
|
if t.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(t.ChainId())
|
||||||
|
}
|
||||||
|
|
||||||
|
from, _ := types.Sender(signer, t)
|
||||||
return &Tx{
|
return &Tx{
|
||||||
tx: t,
|
tx: t,
|
||||||
To: t.To(),
|
To: t.To(),
|
||||||
|
|
@ -1268,7 +1277,11 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
|
||||||
pending := s.b.GetPoolTransactions()
|
pending := s.b.GetPoolTransactions()
|
||||||
transactions := make([]*RPCTransaction, 0, len(pending))
|
transactions := make([]*RPCTransaction, 0, len(pending))
|
||||||
for _, tx := range pending {
|
for _, tx := range pending {
|
||||||
from, _ := tx.FromFrontier()
|
var signer types.Signer = types.HomesteadSigner{}
|
||||||
|
if tx.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(tx.ChainId())
|
||||||
|
}
|
||||||
|
from, _ := types.Sender(signer, tx)
|
||||||
if s.b.AccountManager().HasAddress(from) {
|
if s.b.AccountManager().HasAddress(from) {
|
||||||
transactions = append(transactions, newRPCPendingTransaction(tx))
|
transactions = append(transactions, newRPCPendingTransaction(tx))
|
||||||
}
|
}
|
||||||
|
|
@ -1281,7 +1294,12 @@ func (s *PublicTransactionPoolAPI) PendingTransactions() []*RPCTransaction {
|
||||||
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {
|
func (s *PublicTransactionPoolAPI) Resend(ctx context.Context, tx Tx, gasPrice, gasLimit *rpc.HexNumber) (common.Hash, error) {
|
||||||
pending := s.b.GetPoolTransactions()
|
pending := s.b.GetPoolTransactions()
|
||||||
for _, p := range pending {
|
for _, p := range pending {
|
||||||
if pFrom, err := p.FromFrontier(); err == nil && pFrom == tx.From && p.SigHash() == tx.tx.SigHash() {
|
var signer types.Signer = types.HomesteadSigner{}
|
||||||
|
if p.Protected() {
|
||||||
|
signer = types.NewEIP155Signer(p.ChainId())
|
||||||
|
}
|
||||||
|
|
||||||
|
if pFrom, err := types.Sender(signer, p); err == nil && pFrom == tx.From && signer.Hash(p) == signer.Hash(tx.tx) {
|
||||||
if gasPrice == nil {
|
if gasPrice == nil {
|
||||||
gasPrice = rpc.NewHexNumber(tx.tx.GasPrice())
|
gasPrice = rpc.NewHexNumber(tx.tx.GasPrice())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rpc"
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
@ -59,6 +60,9 @@ 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)
|
||||||
|
|
||||||
|
ChainConfig() *params.ChainConfig
|
||||||
|
CurrentBlock() *types.Block
|
||||||
}
|
}
|
||||||
|
|
||||||
type State interface {
|
type State interface {
|
||||||
|
|
|
||||||
|
|
@ -29,11 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ruleSet struct{}
|
|
||||||
|
|
||||||
func (self *ruleSet) IsHomestead(*big.Int) bool { return true }
|
|
||||||
func (*ruleSet) GasTable(*big.Int) params.GasTable { return params.GasTableHomesteadGasRepriceFork }
|
|
||||||
|
|
||||||
type Env struct {
|
type Env struct {
|
||||||
gasLimit *big.Int
|
gasLimit *big.Int
|
||||||
depth int
|
depth int
|
||||||
|
|
@ -46,7 +41,9 @@ func NewEnv(config *vm.Config) *Env {
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Env) RuleSet() vm.RuleSet { return &ruleSet{} }
|
func (self *Env) ChainConfig() *params.ChainConfig {
|
||||||
|
return params.TestChainConfig
|
||||||
|
}
|
||||||
func (self *Env) Vm() vm.Vm { return self.evm }
|
func (self *Env) Vm() vm.Vm { return self.evm }
|
||||||
func (self *Env) Origin() common.Address { return common.Address{} }
|
func (self *Env) Origin() common.Address { return common.Address{} }
|
||||||
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
func (self *Env) BlockNumber() *big.Int { return big.NewInt(0) }
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/internal/ethapi"
|
"github.com/ethereum/go-ethereum/internal/ethapi"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
@ -39,6 +40,14 @@ type LesApiBackend struct {
|
||||||
gpo *gasprice.LightPriceOracle
|
gpo *gasprice.LightPriceOracle
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) ChainConfig() *params.ChainConfig {
|
||||||
|
return b.eth.chainConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) CurrentBlock() *types.Block {
|
||||||
|
return types.NewBlockWithHeader(b.eth.BlockChain().CurrentHeader())
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) SetHead(number uint64) {
|
func (b *LesApiBackend) SetHead(number uint64) {
|
||||||
b.eth.blockchain.SetHead(number)
|
b.eth.blockchain.SetHead(number)
|
||||||
}
|
}
|
||||||
|
|
@ -81,13 +90,13 @@ func (b *LesApiBackend) GetTd(blockHash common.Hash) *big.Int {
|
||||||
|
|
||||||
func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
func (b *LesApiBackend) GetVMEnv(ctx context.Context, msg core.Message, state ethapi.State, header *types.Header) (vm.Environment, func() error, error) {
|
||||||
stateDb := state.(*light.LightState).Copy()
|
stateDb := state.(*light.LightState).Copy()
|
||||||
addr, _ := msg.From()
|
addr := msg.From()
|
||||||
from, err := stateDb.GetOrNewStateObject(ctx, addr)
|
from, err := stateDb.GetOrNewStateObject(ctx, addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, b.eth.chainConfig.VmConfig)
|
env := light.NewEnv(ctx, stateDb, b.eth.chainConfig, b.eth.blockchain, msg, header, vm.Config{})
|
||||||
return env, env.Error, nil
|
return env, env.Error, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/httpclient"
|
"github.com/ethereum/go-ethereum/common/httpclient"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"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/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
|
|
@ -42,13 +41,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
rpc "github.com/ethereum/go-ethereum/rpc"
|
rpc "github.com/ethereum/go-ethereum/rpc"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LightEthereum struct {
|
type LightEthereum struct {
|
||||||
odr *LesOdr
|
odr *LesOdr
|
||||||
relay *LesTxRelay
|
relay *LesTxRelay
|
||||||
chainConfig *core.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
// Channel for shutting down the service
|
// Channel for shutting down the service
|
||||||
shutdownChan chan bool
|
shutdownChan chan bool
|
||||||
// Handlers
|
// Handlers
|
||||||
|
|
@ -107,10 +107,6 @@ func New(ctx *node.ServiceContext, config *eth.Config) (*LightEthereum, error) {
|
||||||
return nil, errors.New("missing chain config")
|
return nil, errors.New("missing chain config")
|
||||||
}
|
}
|
||||||
eth.chainConfig = config.ChainConfig
|
eth.chainConfig = config.ChainConfig
|
||||||
eth.chainConfig.VmConfig = vm.Config{
|
|
||||||
EnableJit: config.EnableJit,
|
|
||||||
ForceJit: config.ForceJit,
|
|
||||||
}
|
|
||||||
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
|
eth.blockchain, err = light.NewLightChain(odr, eth.chainConfig, eth.pow, eth.eventMux)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == core.ErrNoGenesis {
|
if err == core.ErrNoGenesis {
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ type ServerNode struct {
|
||||||
params *ServerParams
|
params *ServerParams
|
||||||
sumCost uint64 // sum of req costs sent to this server
|
sumCost uint64 // sum of req costs sent to this server
|
||||||
pending map[uint64]uint64 // value = sumCost after sending the given req
|
pending map[uint64]uint64 // value = sumCost after sending the given req
|
||||||
lock sync.Mutex
|
lock sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServerNode(params *ServerParams) *ServerNode {
|
func NewServerNode(params *ServerParams) *ServerNode {
|
||||||
|
|
@ -135,8 +135,8 @@ func (peer *ServerNode) canSend(maxCost uint64) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (peer *ServerNode) CanSend(maxCost uint64) uint64 {
|
func (peer *ServerNode) CanSend(maxCost uint64) uint64 {
|
||||||
peer.lock.Lock()
|
peer.lock.RLock()
|
||||||
defer peer.lock.Unlock()
|
defer peer.lock.RUnlock()
|
||||||
|
|
||||||
return peer.canSend(maxCost)
|
return peer.canSend(maxCost)
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +148,10 @@ func (peer *ServerNode) SendRequest(reqID, maxCost uint64) {
|
||||||
|
|
||||||
peer.recalcBLE(getTime())
|
peer.recalcBLE(getTime())
|
||||||
for peer.bufEstimate < maxCost {
|
for peer.bufEstimate < maxCost {
|
||||||
time.Sleep(time.Duration(peer.canSend(maxCost)))
|
wait := time.Duration(peer.canSend(maxCost))
|
||||||
|
peer.lock.Unlock()
|
||||||
|
time.Sleep(wait)
|
||||||
|
peer.lock.Lock()
|
||||||
peer.recalcBLE(getTime())
|
peer.recalcBLE(getTime())
|
||||||
}
|
}
|
||||||
peer.bufEstimate -= maxCost
|
peer.bufEstimate -= maxCost
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
"github.com/ethereum/go-ethereum/p2p/discover"
|
||||||
"github.com/ethereum/go-ethereum/p2p/discv5"
|
"github.com/ethereum/go-ethereum/p2p/discv5"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
|
@ -95,7 +96,7 @@ type ProtocolManager struct {
|
||||||
txpool txPool
|
txpool txPool
|
||||||
txrelay *LesTxRelay
|
txrelay *LesTxRelay
|
||||||
networkId int
|
networkId int
|
||||||
chainConfig *core.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
blockchain BlockChain
|
blockchain BlockChain
|
||||||
chainDb ethdb.Database
|
chainDb ethdb.Database
|
||||||
odr *LesOdr
|
odr *LesOdr
|
||||||
|
|
@ -129,7 +130,7 @@ type ProtocolManager struct {
|
||||||
|
|
||||||
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
|
||||||
// with the ethereum network.
|
// with the ethereum network.
|
||||||
func NewProtocolManager(chainConfig *core.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
|
func NewProtocolManager(chainConfig *params.ChainConfig, lightSync bool, networkId int, mux *event.TypeMux, pow pow.PoW, blockchain BlockChain, txpool txPool, chainDb ethdb.Database, odr *LesOdr, txrelay *LesTxRelay) (*ProtocolManager, error) {
|
||||||
// Create the protocol manager with the base fields
|
// Create the protocol manager with the base fields
|
||||||
manager := &ProtocolManager{
|
manager := &ProtocolManager{
|
||||||
lightSync: lightSync,
|
lightSync: lightSync,
|
||||||
|
|
@ -239,6 +240,7 @@ func (pm *ProtocolManager) findServers() {
|
||||||
if pm.p2pServer == nil || pm.topicDisc == nil {
|
if pm.p2pServer == nil || pm.topicDisc == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
glog.V(logger.Debug).Infoln("Looking for topic", string(pm.lesTopic))
|
||||||
enodes := make(chan string, 100)
|
enodes := make(chan string, 100)
|
||||||
stop := make(chan struct{})
|
stop := make(chan struct{})
|
||||||
go pm.topicDisc.SearchTopic(pm.lesTopic, stop, enodes)
|
go pm.topicDisc.SearchTopic(pm.lesTopic, stop, enodes)
|
||||||
|
|
@ -279,9 +281,9 @@ func (pm *ProtocolManager) Start(srvr *p2p.Server) {
|
||||||
} else {
|
} else {
|
||||||
if pm.topicDisc != nil {
|
if pm.topicDisc != nil {
|
||||||
go func() {
|
go func() {
|
||||||
glog.V(logger.Debug).Infoln("Starting topic register")
|
glog.V(logger.Debug).Infoln("Starting registering topic", string(pm.lesTopic))
|
||||||
pm.topicDisc.RegisterTopic(pm.lesTopic, pm.quitSync)
|
pm.topicDisc.RegisterTopic(pm.lesTopic, pm.quitSync)
|
||||||
glog.V(logger.Debug).Infoln("Stopped topic register")
|
glog.V(logger.Debug).Infoln("Stopped registering topic", string(pm.lesTopic))
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
|
|
|
||||||
|
|
@ -73,20 +73,22 @@ contract test {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
func testChainGen(i int, block *core.BlockGen) {
|
func testChainGen(i int, block *core.BlockGen) {
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
|
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// In block 1, the test bank sends account #1 some ether.
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// acc1Addr passes it on to account #2.
|
||||||
// acc1Addr creates a test contract.
|
// acc1Addr creates a test contract.
|
||||||
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
nonce := block.TxNonce(acc1Addr)
|
nonce := block.TxNonce(acc1Addr)
|
||||||
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
|
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
|
||||||
nonce++
|
nonce++
|
||||||
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(acc1Key)
|
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(200000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
|
||||||
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
|
|
@ -96,7 +98,7 @@ func testChainGen(i int, block *core.BlockGen) {
|
||||||
block.SetCoinbase(acc2Addr)
|
block.SetCoinbase(acc2Addr)
|
||||||
block.SetExtra([]byte("yeehaw"))
|
block.SetExtra([]byte("yeehaw"))
|
||||||
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
|
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 3:
|
case 3:
|
||||||
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
|
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
|
||||||
|
|
@ -107,7 +109,7 @@ func testChainGen(i int, block *core.BlockGen) {
|
||||||
b3.Extra = []byte("foo")
|
b3.Extra = []byte("foo")
|
||||||
block.AddUncle(b3)
|
block.AddUncle(b3)
|
||||||
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
|
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,7 +133,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
pow = new(core.FakePow)
|
pow = new(core.FakePow)
|
||||||
db, _ = ethdb.NewMemDatabase()
|
db, _ = ethdb.NewMemDatabase()
|
||||||
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
genesis = core.WriteGenesisBlockForTesting(db, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
||||||
chainConfig = &core.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
chainConfig = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)} // homestead set to 0 because of chain maker
|
||||||
odr *LesOdr
|
odr *LesOdr
|
||||||
chain BlockChain
|
chain BlockChain
|
||||||
)
|
)
|
||||||
|
|
@ -141,7 +143,7 @@ func newTestProtocolManager(lightSync bool, blocks int, generator func(int, *cor
|
||||||
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
|
chain, _ = light.NewLightChain(odr, chainConfig, pow, evmux)
|
||||||
} else {
|
} else {
|
||||||
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux)
|
blockchain, _ := core.NewBlockChain(db, chainConfig, pow, evmux)
|
||||||
gchain, _ := core.GenerateChain(nil, genesis, db, blocks, generator)
|
gchain, _ := core.GenerateChain(chainConfig, genesis, db, blocks, generator)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
@ -214,7 +216,7 @@ func (p *testTxPool) GetTransactions() types.Transactions {
|
||||||
// newTestTransaction create a new dummy transaction.
|
// newTestTransaction create a new dummy transaction.
|
||||||
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
|
func newTestTransaction(from *ecdsa.PrivateKey, nonce uint64, datasize int) *types.Transaction {
|
||||||
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
|
tx := types.NewTransaction(nonce, common.Address{}, big.NewInt(0), big.NewInt(100000), big.NewInt(0), make([]byte, datasize))
|
||||||
tx, _ = tx.SignECDSA(from)
|
tx, _ = tx.SignECDSA(types.HomesteadSigner{}, from)
|
||||||
|
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,17 +26,19 @@ import (
|
||||||
"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/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/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/light"
|
"github.com/ethereum/go-ethereum/light"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
type odrTestFn func(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
|
type odrTestFn func(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte
|
||||||
|
|
||||||
func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
|
func TestOdrGetBlockLes1(t *testing.T) { testOdr(t, 1, 1, odrGetBlock) }
|
||||||
|
|
||||||
func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
func odrGetBlock(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
var block *types.Block
|
var block *types.Block
|
||||||
if bc != nil {
|
if bc != nil {
|
||||||
block = bc.GetBlockByHash(bhash)
|
block = bc.GetBlockByHash(bhash)
|
||||||
|
|
@ -52,7 +54,7 @@ func odrGetBlock(ctx context.Context, db ethdb.Database, config *core.ChainConfi
|
||||||
|
|
||||||
func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) }
|
func TestOdrGetReceiptsLes1(t *testing.T) { testOdr(t, 1, 1, odrGetReceipts) }
|
||||||
|
|
||||||
func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
func odrGetReceipts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
var receipts types.Receipts
|
var receipts types.Receipts
|
||||||
if bc != nil {
|
if bc != nil {
|
||||||
receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash))
|
receipts = core.GetBlockReceipts(db, bhash, core.GetBlockNumber(db, bhash))
|
||||||
|
|
@ -68,7 +70,7 @@ func odrGetReceipts(ctx context.Context, db ethdb.Database, config *core.ChainCo
|
||||||
|
|
||||||
func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) }
|
func TestOdrAccountsLes1(t *testing.T) { testOdr(t, 1, 1, odrAccounts) }
|
||||||
|
|
||||||
func odrAccounts(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
func odrAccounts(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
|
dummyAddr := common.HexToAddress("1234567812345678123456781234567812345678")
|
||||||
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
|
acc := []common.Address{testBankAddress, acc1Addr, acc2Addr, dummyAddr}
|
||||||
|
|
||||||
|
|
@ -98,47 +100,13 @@ func odrAccounts(ctx context.Context, db ethdb.Database, config *core.ChainConfi
|
||||||
|
|
||||||
func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) }
|
func TestOdrContractCallLes1(t *testing.T) { testOdr(t, 1, 2, odrContractCall) }
|
||||||
|
|
||||||
// fullcallmsg is the message type used for call transations.
|
type callmsg struct {
|
||||||
type fullcallmsg struct {
|
types.Message
|
||||||
from *state.StateObject
|
|
||||||
to *common.Address
|
|
||||||
gas, gasPrice *big.Int
|
|
||||||
value *big.Int
|
|
||||||
data []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor boilerplate to implement core.Message
|
func (callmsg) CheckNonce() bool { return false }
|
||||||
func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m fullcallmsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m fullcallmsg) CheckNonce() bool { return false }
|
|
||||||
func (m fullcallmsg) To() *common.Address { return m.to }
|
|
||||||
func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m fullcallmsg) Gas() *big.Int { return m.gas }
|
|
||||||
func (m fullcallmsg) Value() *big.Int { return m.value }
|
|
||||||
func (m fullcallmsg) Data() []byte { return m.data }
|
|
||||||
|
|
||||||
// callmsg is the message type used for call transations.
|
func odrContractCall(ctx context.Context, db ethdb.Database, config *params.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
||||||
type lightcallmsg struct {
|
|
||||||
from *light.StateObject
|
|
||||||
to *common.Address
|
|
||||||
gas, gasPrice *big.Int
|
|
||||||
value *big.Int
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// accessor boilerplate to implement core.Message
|
|
||||||
func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m lightcallmsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m lightcallmsg) CheckNonce() bool { return false }
|
|
||||||
func (m lightcallmsg) To() *common.Address { return m.to }
|
|
||||||
func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m lightcallmsg) Gas() *big.Int { return m.gas }
|
|
||||||
func (m lightcallmsg) Value() *big.Int { return m.value }
|
|
||||||
func (m lightcallmsg) Data() []byte { return m.data }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainConfig, bc *core.BlockChain, lc *light.LightChain, bhash common.Hash) []byte {
|
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
||||||
var res []byte
|
var res []byte
|
||||||
|
|
@ -151,16 +119,8 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
|
||||||
from := statedb.GetOrNewStateObject(testBankAddress)
|
from := statedb.GetOrNewStateObject(testBankAddress)
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
||||||
msg := fullcallmsg{
|
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)}
|
||||||
from: from,
|
vmenv := core.NewEnv(statedb, config, bc, msg, header, vm.Config{})
|
||||||
gas: big.NewInt(100000),
|
|
||||||
gasPrice: big.NewInt(0),
|
|
||||||
value: big.NewInt(0),
|
|
||||||
data: data,
|
|
||||||
to: &testContractAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
vmenv := core.NewEnv(statedb, config, bc, msg, header, config.VmConfig)
|
|
||||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
res = append(res, ret...)
|
res = append(res, ret...)
|
||||||
|
|
@ -172,16 +132,9 @@ func odrContractCall(ctx context.Context, db ethdb.Database, config *core.ChainC
|
||||||
if err == nil {
|
if err == nil {
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
||||||
msg := lightcallmsg{
|
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(100000), new(big.Int), data, false)}
|
||||||
from: from,
|
|
||||||
gas: big.NewInt(100000),
|
|
||||||
gasPrice: big.NewInt(0),
|
|
||||||
value: big.NewInt(0),
|
|
||||||
data: data,
|
|
||||||
to: &testContractAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
vmenv := light.NewEnv(ctx, state, config, lc, msg, header, config.VmConfig)
|
vmenv := light.NewEnv(ctx, state, config, lc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
if vmenv.Error() == nil {
|
if vmenv.Error() == nil {
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
|
|
@ -71,7 +72,7 @@ type LightChain struct {
|
||||||
// NewLightChain returns a fully initialised light chain using information
|
// NewLightChain returns a fully initialised light chain using information
|
||||||
// available in the database. It initialises the default Ethereum header
|
// available in the database. It initialises the default Ethereum header
|
||||||
// validator.
|
// validator.
|
||||||
func NewLightChain(odr OdrBackend, config *core.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
|
func NewLightChain(odr OdrBackend, config *params.ChainConfig, pow pow.PoW, mux *event.TypeMux) (*LightChain, error) {
|
||||||
bodyCache, _ := lru.New(bodyCacheLimit)
|
bodyCache, _ := lru.New(bodyCacheLimit)
|
||||||
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
bodyRLPCache, _ := lru.New(bodyCacheLimit)
|
||||||
blockCache, _ := lru.New(blockCacheLimit)
|
blockCache, _ := lru.New(blockCacheLimit)
|
||||||
|
|
@ -107,8 +108,8 @@ func NewLightChain(odr OdrBackend, config *core.ChainConfig, pow pow.PoW, mux *e
|
||||||
// add trusted CHT
|
// add trusted CHT
|
||||||
if config.DAOForkSupport {
|
if config.DAOForkSupport {
|
||||||
WriteTrustedCht(bc.chainDb, TrustedCht{
|
WriteTrustedCht(bc.chainDb, TrustedCht{
|
||||||
Number: 612,
|
Number: 637,
|
||||||
Root: common.HexToHash("8c87a93e0ee531e2aca1b4460e4c201a60c19ffec4f5979262bf14ceeeff8471"),
|
Root: common.HexToHash("01e408d9b1942f05dba1a879f3eaafe34d219edaeb8223fecf1244cc023d3e23"),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
WriteTrustedCht(bc.chainDb, TrustedCht{
|
WriteTrustedCht(bc.chainDb, TrustedCht{
|
||||||
|
|
@ -121,8 +122,8 @@ func NewLightChain(odr OdrBackend, config *core.ChainConfig, pow pow.PoW, mux *e
|
||||||
if bc.genesisBlock.Hash() == (common.Hash{12, 215, 134, 162, 66, 93, 22, 241, 82, 198, 88, 49, 108, 66, 62, 108, 225, 24, 30, 21, 195, 41, 88, 38, 215, 201, 144, 76, 186, 156, 227, 3}) {
|
if bc.genesisBlock.Hash() == (common.Hash{12, 215, 134, 162, 66, 93, 22, 241, 82, 198, 88, 49, 108, 66, 62, 108, 225, 24, 30, 21, 195, 41, 88, 38, 215, 201, 144, 76, 186, 156, 227, 3}) {
|
||||||
// add trusted CHT for testnet
|
// add trusted CHT for testnet
|
||||||
WriteTrustedCht(bc.chainDb, TrustedCht{
|
WriteTrustedCht(bc.chainDb, TrustedCht{
|
||||||
Number: 436,
|
Number: 452,
|
||||||
Root: common.HexToHash("97a12df5d04d72bde4b4b840e1018e4f08aee34b7d0bf2c5dbfc052b86fe7439"),
|
Root: common.HexToHash("511da2c88e32b14cf4a4e62f7fcbb297139faebc260a4ab5eb43cce6edcba324"),
|
||||||
})
|
})
|
||||||
glog.V(logger.Info).Infoln("Added trusted CHT for testnet")
|
glog.V(logger.Info).Infoln("Added trusted CHT for testnet")
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/pow"
|
"github.com/ethereum/go-ethereum/pow"
|
||||||
"github.com/hashicorp/golang-lru"
|
"github.com/hashicorp/golang-lru"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
@ -41,7 +42,7 @@ var (
|
||||||
|
|
||||||
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
|
// makeHeaderChain creates a deterministic chain of headers rooted at parent.
|
||||||
func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
|
func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) []*types.Header {
|
||||||
blocks, _ := core.GenerateChain(nil, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) {
|
blocks, _ := core.GenerateChain(params.TestChainConfig, types.NewBlockWithHeader(parent), db, n, func(i int, b *core.BlockGen) {
|
||||||
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
b.SetCoinbase(common.Address{0: byte(seed), 19: byte(i)})
|
||||||
})
|
})
|
||||||
headers := make([]*types.Header, len(blocks))
|
headers := make([]*types.Header, len(blocks))
|
||||||
|
|
@ -51,8 +52,8 @@ func makeHeaderChain(parent *types.Header, n int, db ethdb.Database, seed int) [
|
||||||
return headers
|
return headers
|
||||||
}
|
}
|
||||||
|
|
||||||
func testChainConfig() *core.ChainConfig {
|
func testChainConfig() *params.ChainConfig {
|
||||||
return &core.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
return ¶ms.ChainConfig{HomesteadBlock: big.NewInt(0)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCanonical creates a chain database, and injects a deterministic canonical
|
// newCanonical creates a chain database, and injects a deterministic canonical
|
||||||
|
|
|
||||||
|
|
@ -148,45 +148,11 @@ func odrAccounts(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc
|
||||||
|
|
||||||
func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) }
|
func TestOdrContractCallLes1(t *testing.T) { testChainOdr(t, 1, 2, odrContractCall) }
|
||||||
|
|
||||||
// fullcallmsg is the message type used for call transations.
|
type callmsg struct {
|
||||||
type fullcallmsg struct {
|
types.Message
|
||||||
from *state.StateObject
|
|
||||||
to *common.Address
|
|
||||||
gas, gasPrice *big.Int
|
|
||||||
value *big.Int
|
|
||||||
data []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// accessor boilerplate to implement core.Message
|
func (callmsg) CheckNonce() bool { return false }
|
||||||
func (m fullcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m fullcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m fullcallmsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m fullcallmsg) CheckNonce() bool { return false }
|
|
||||||
func (m fullcallmsg) To() *common.Address { return m.to }
|
|
||||||
func (m fullcallmsg) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m fullcallmsg) Gas() *big.Int { return m.gas }
|
|
||||||
func (m fullcallmsg) Value() *big.Int { return m.value }
|
|
||||||
func (m fullcallmsg) Data() []byte { return m.data }
|
|
||||||
|
|
||||||
// callmsg is the message type used for call transations.
|
|
||||||
type lightcallmsg struct {
|
|
||||||
from *StateObject
|
|
||||||
to *common.Address
|
|
||||||
gas, gasPrice *big.Int
|
|
||||||
value *big.Int
|
|
||||||
data []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// accessor boilerplate to implement core.Message
|
|
||||||
func (m lightcallmsg) From() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m lightcallmsg) FromFrontier() (common.Address, error) { return m.from.Address(), nil }
|
|
||||||
func (m lightcallmsg) Nonce() uint64 { return 0 }
|
|
||||||
func (m lightcallmsg) CheckNonce() bool { return false }
|
|
||||||
func (m lightcallmsg) To() *common.Address { return m.to }
|
|
||||||
func (m lightcallmsg) GasPrice() *big.Int { return m.gasPrice }
|
|
||||||
func (m lightcallmsg) Gas() *big.Int { return m.gas }
|
|
||||||
func (m lightcallmsg) Value() *big.Int { return m.value }
|
|
||||||
func (m lightcallmsg) Data() []byte { return m.data }
|
|
||||||
|
|
||||||
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte {
|
func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain, lc *LightChain, bhash common.Hash) []byte {
|
||||||
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
data := common.Hex2Bytes("60CD26850000000000000000000000000000000000000000000000000000000000000000")
|
||||||
|
|
@ -201,15 +167,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
from := statedb.GetOrNewStateObject(testBankAddress)
|
from := statedb.GetOrNewStateObject(testBankAddress)
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
||||||
msg := fullcallmsg{
|
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)}
|
||||||
from: from,
|
|
||||||
gas: big.NewInt(100000),
|
|
||||||
gasPrice: big.NewInt(0),
|
|
||||||
value: big.NewInt(0),
|
|
||||||
data: data,
|
|
||||||
to: &testContractAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{})
|
vmenv := core.NewEnv(statedb, testChainConfig(), bc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
|
|
@ -222,15 +180,7 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
if err == nil {
|
if err == nil {
|
||||||
from.SetBalance(common.MaxBig)
|
from.SetBalance(common.MaxBig)
|
||||||
|
|
||||||
msg := lightcallmsg{
|
msg := callmsg{types.NewMessage(from.Address(), &testContractAddr, 0, new(big.Int), big.NewInt(1000000), new(big.Int), data, false)}
|
||||||
from: from,
|
|
||||||
gas: big.NewInt(100000),
|
|
||||||
gasPrice: big.NewInt(0),
|
|
||||||
value: big.NewInt(0),
|
|
||||||
data: data,
|
|
||||||
to: &testContractAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{})
|
vmenv := NewEnv(ctx, state, testChainConfig(), lc, msg, header, vm.Config{})
|
||||||
gp := new(core.GasPool).AddGas(common.MaxBig)
|
gp := new(core.GasPool).AddGas(common.MaxBig)
|
||||||
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
ret, _, _ := core.ApplyMessage(vmenv, msg, gp)
|
||||||
|
|
@ -244,20 +194,21 @@ func odrContractCall(ctx context.Context, db ethdb.Database, bc *core.BlockChain
|
||||||
}
|
}
|
||||||
|
|
||||||
func testChainGen(i int, block *core.BlockGen) {
|
func testChainGen(i int, block *core.BlockGen) {
|
||||||
|
signer := types.HomesteadSigner{}
|
||||||
switch i {
|
switch i {
|
||||||
case 0:
|
case 0:
|
||||||
// In block 1, the test bank sends account #1 some ether.
|
// In block 1, the test bank sends account #1 some ether.
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 1:
|
case 1:
|
||||||
// In block 2, the test bank sends some more ether to account #1.
|
// In block 2, the test bank sends some more ether to account #1.
|
||||||
// acc1Addr passes it on to account #2.
|
// acc1Addr passes it on to account #2.
|
||||||
// acc1Addr creates a test contract.
|
// acc1Addr creates a test contract.
|
||||||
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, testBankKey)
|
||||||
nonce := block.TxNonce(acc1Addr)
|
nonce := block.TxNonce(acc1Addr)
|
||||||
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key)
|
tx2, _ := types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(signer, acc1Key)
|
||||||
nonce++
|
nonce++
|
||||||
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(acc1Key)
|
tx3, _ := types.NewContractCreation(nonce, big.NewInt(0), big.NewInt(1000000), big.NewInt(0), testContractCode).SignECDSA(signer, acc1Key)
|
||||||
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
|
|
@ -267,7 +218,7 @@ func testChainGen(i int, block *core.BlockGen) {
|
||||||
block.SetCoinbase(acc2Addr)
|
block.SetCoinbase(acc2Addr)
|
||||||
block.SetExtra([]byte("yeehaw"))
|
block.SetExtra([]byte("yeehaw"))
|
||||||
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
|
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001")
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
case 3:
|
case 3:
|
||||||
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
|
// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
|
||||||
|
|
@ -278,7 +229,7 @@ func testChainGen(i int, block *core.BlockGen) {
|
||||||
b3.Extra = []byte("foo")
|
b3.Extra = []byte("foo")
|
||||||
block.AddUncle(b3)
|
block.AddUncle(b3)
|
||||||
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
|
data := common.Hex2Bytes("C16431B900000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002")
|
||||||
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(testBankKey)
|
tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), testContractAddr, big.NewInt(0), big.NewInt(100000), nil, data).SignECDSA(signer, testBankKey)
|
||||||
block.AddTx(tx)
|
block.AddTx(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -294,7 +245,8 @@ func testChainOdr(t *testing.T, protocol int, expFail uint64, fn odrTestFn) {
|
||||||
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
|
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
|
||||||
gchain, _ := core.GenerateChain(nil, genesis, sdb, 4, testChainGen)
|
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||||
|
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, 4, testChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
|
||||||
st.AddBalance(addr, big.NewInt(int64(i)))
|
st.AddBalance(addr, big.NewInt(int64(i)))
|
||||||
st.SetCode(addr, []byte{i, i, i})
|
st.SetCode(addr, []byte{i, i, i})
|
||||||
}
|
}
|
||||||
root, _ := st.Commit()
|
root, _ := st.Commit(false)
|
||||||
return root, sdb
|
return root, sdb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/logger"
|
"github.com/ethereum/go-ethereum/logger"
|
||||||
"github.com/ethereum/go-ethereum/logger/glog"
|
"github.com/ethereum/go-ethereum/logger/glog"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
@ -42,7 +43,8 @@ var txPermanent = uint64(500)
|
||||||
// always receive all locally signed transactions in the same order as they are
|
// always receive all locally signed transactions in the same order as they are
|
||||||
// created.
|
// created.
|
||||||
type TxPool struct {
|
type TxPool struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
|
signer types.Signer
|
||||||
quit chan bool
|
quit chan bool
|
||||||
eventMux *event.TypeMux
|
eventMux *event.TypeMux
|
||||||
events event.Subscription
|
events event.Subscription
|
||||||
|
|
@ -76,9 +78,10 @@ type TxRelayBackend interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTxPool creates a new light transaction pool
|
// NewTxPool creates a new light transaction pool
|
||||||
func NewTxPool(config *core.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
|
func NewTxPool(config *params.ChainConfig, eventMux *event.TypeMux, chain *LightChain, relay TxRelayBackend) *TxPool {
|
||||||
pool := &TxPool{
|
pool := &TxPool{
|
||||||
config: config,
|
config: config,
|
||||||
|
signer: types.HomesteadSigner{},
|
||||||
nonce: make(map[common.Address]uint64),
|
nonce: make(map[common.Address]uint64),
|
||||||
pending: make(map[common.Hash]*types.Transaction),
|
pending: make(map[common.Hash]*types.Transaction),
|
||||||
mined: make(map[common.Hash][]*types.Transaction),
|
mined: make(map[common.Hash][]*types.Transaction),
|
||||||
|
|
@ -197,7 +200,7 @@ func (pool *TxPool) checkMinedTxs(ctx context.Context, hash common.Hash, idx uin
|
||||||
if len(receipts) != len(block.Transactions()) {
|
if len(receipts) != len(block.Transactions()) {
|
||||||
panic(nil) // should never happen if hashes did match
|
panic(nil) // should never happen if hashes did match
|
||||||
}
|
}
|
||||||
core.SetReceiptsData(block, receipts)
|
core.SetReceiptsData(pool.config, block, receipts)
|
||||||
}
|
}
|
||||||
//fmt.Println("WriteReceipt", receipts[i].TxHash)
|
//fmt.Println("WriteReceipt", receipts[i].TxHash)
|
||||||
core.WriteReceipt(pool.chainDb, receipts[i])
|
core.WriteReceipt(pool.chainDb, receipts[i])
|
||||||
|
|
@ -308,6 +311,7 @@ func (pool *TxPool) eventLoop() {
|
||||||
m, r := txc.getLists()
|
m, r := txc.getLists()
|
||||||
pool.relay.NewHead(pool.head, m, r)
|
pool.relay.NewHead(pool.head, m, r)
|
||||||
pool.homestead = pool.config.IsHomestead(head.Number)
|
pool.homestead = pool.config.IsHomestead(head.Number)
|
||||||
|
pool.signer = types.MakeSigner(pool.config, head.Number)
|
||||||
pool.mu.Unlock()
|
pool.mu.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -339,7 +343,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
|
||||||
|
|
||||||
// Validate the transaction sender and it's sig. Throw
|
// Validate the transaction sender and it's sig. Throw
|
||||||
// if the from fields is invalid.
|
// if the from fields is invalid.
|
||||||
if from, err = tx.From(); err != nil {
|
if from, err = types.Sender(pool.signer, tx); err != nil {
|
||||||
return core.ErrInvalidSender
|
return core.ErrInvalidSender
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -388,7 +392,7 @@ func (pool *TxPool) validateTx(ctx context.Context, tx *types.Transaction) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Should supply enough intrinsic gas
|
// Should supply enough intrinsic gas
|
||||||
if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), core.MessageCreatesContract(tx), pool.homestead)) < 0 {
|
if tx.Gas().Cmp(core.IntrinsicGas(tx.Data(), tx.To() == nil, pool.homestead)) < 0 {
|
||||||
return core.ErrIntrinsicGas
|
return core.ErrIntrinsicGas
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -412,7 +416,8 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
|
||||||
self.pending[hash] = tx
|
self.pending[hash] = tx
|
||||||
|
|
||||||
nonce := tx.Nonce() + 1
|
nonce := tx.Nonce() + 1
|
||||||
addr, _ := tx.From()
|
|
||||||
|
addr, _ := types.Sender(self.signer, tx)
|
||||||
if nonce > self.nonce[addr] {
|
if nonce > self.nonce[addr] {
|
||||||
self.nonce[addr] = nonce
|
self.nonce[addr] = nonce
|
||||||
}
|
}
|
||||||
|
|
@ -432,7 +437,7 @@ func (self *TxPool) add(ctx context.Context, tx *types.Transaction) error {
|
||||||
}
|
}
|
||||||
// we can ignore the error here because From is
|
// we can ignore the error here because From is
|
||||||
// verified in ValidateTransaction.
|
// verified in ValidateTransaction.
|
||||||
f, _ := tx.From()
|
f, _ := types.Sender(self.signer, tx)
|
||||||
from := common.Bytes2Hex(f[:4])
|
from := common.Bytes2Hex(f[:4])
|
||||||
glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash)
|
glog.Infof("(t) %x => %s (%v) %x\n", from, toname, tx.Value, hash)
|
||||||
}
|
}
|
||||||
|
|
@ -517,7 +522,7 @@ func (self *TxPool) Content() (map[common.Address]types.Transactions, map[common
|
||||||
// Retrieve all the pending transactions and sort by account and by nonce
|
// Retrieve all the pending transactions and sort by account and by nonce
|
||||||
pending := make(map[common.Address]types.Transactions)
|
pending := make(map[common.Address]types.Transactions)
|
||||||
for _, tx := range self.pending {
|
for _, tx := range self.pending {
|
||||||
account, _ := tx.From()
|
account, _ := types.Sender(self.signer, tx)
|
||||||
pending[account] = append(pending[account], tx)
|
pending[account] = append(pending[account], tx)
|
||||||
}
|
}
|
||||||
// There are no queued transactions in a light pool, just return an empty map
|
// There are no queued transactions in a light pool, just return an empty map
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ func txPoolTestChainGen(i int, block *core.BlockGen) {
|
||||||
|
|
||||||
func TestTxPool(t *testing.T) {
|
func TestTxPool(t *testing.T) {
|
||||||
for i, _ := range testTx {
|
for i, _ := range testTx {
|
||||||
testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey)
|
testTx[i], _ = types.NewTransaction(uint64(i), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(types.HomesteadSigner{}, testBankKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -87,7 +87,8 @@ func TestTxPool(t *testing.T) {
|
||||||
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
core.WriteGenesisBlockForTesting(ldb, core.GenesisAccount{Address: testBankAddress, Balance: testBankFunds})
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
|
blockchain, _ := core.NewBlockChain(sdb, testChainConfig(), pow, evmux)
|
||||||
gchain, _ := core.GenerateChain(nil, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
|
chainConfig := ¶ms.ChainConfig{HomesteadBlock: new(big.Int)}
|
||||||
|
gchain, _ := core.GenerateChain(chainConfig, genesis, sdb, poolTestBlocks, txPoolTestChainGen)
|
||||||
if _, err := blockchain.InsertChain(gchain); err != nil {
|
if _, err := blockchain.InsertChain(gchain); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"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/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -34,7 +35,7 @@ import (
|
||||||
type VMEnv struct {
|
type VMEnv struct {
|
||||||
vm.Environment
|
vm.Environment
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
chainConfig *core.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
state *VMState
|
state *VMState
|
||||||
header *types.Header
|
header *types.Header
|
||||||
|
|
@ -45,7 +46,7 @@ type VMEnv struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewEnv creates a new execution environment based on an ODR capable light state
|
// NewEnv creates a new execution environment based on an ODR capable light state
|
||||||
func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv {
|
func NewEnv(ctx context.Context, state *LightState, chainConfig *params.ChainConfig, chain *LightChain, msg core.Message, header *types.Header, cfg vm.Config) *VMEnv {
|
||||||
env := &VMEnv{
|
env := &VMEnv{
|
||||||
chainConfig: chainConfig,
|
chainConfig: chainConfig,
|
||||||
chain: chain,
|
chain: chain,
|
||||||
|
|
@ -58,17 +59,17 @@ func NewEnv(ctx context.Context, state *LightState, chainConfig *core.ChainConfi
|
||||||
return env
|
return env
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VMEnv) RuleSet() vm.RuleSet { return self.chainConfig }
|
func (self *VMEnv) ChainConfig() *params.ChainConfig { return self.chainConfig }
|
||||||
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
func (self *VMEnv) Vm() vm.Vm { return self.evm }
|
||||||
func (self *VMEnv) Origin() common.Address { f, _ := self.msg.From(); return f }
|
func (self *VMEnv) Origin() common.Address { return self.msg.From() }
|
||||||
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
func (self *VMEnv) BlockNumber() *big.Int { return self.header.Number }
|
||||||
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
func (self *VMEnv) Coinbase() common.Address { return self.header.Coinbase }
|
||||||
func (self *VMEnv) Time() *big.Int { return self.header.Time }
|
func (self *VMEnv) Time() *big.Int { return self.header.Time }
|
||||||
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
|
func (self *VMEnv) Difficulty() *big.Int { return self.header.Difficulty }
|
||||||
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
|
func (self *VMEnv) GasLimit() *big.Int { return self.header.GasLimit }
|
||||||
func (self *VMEnv) Db() vm.Database { return self.state }
|
func (self *VMEnv) Db() vm.Database { return self.state }
|
||||||
func (self *VMEnv) Depth() int { return self.depth }
|
func (self *VMEnv) Depth() int { return self.depth }
|
||||||
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
func (self *VMEnv) SetDepth(i int) { self.depth = i }
|
||||||
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
func (self *VMEnv) GetHash(n uint64) common.Hash {
|
||||||
for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
|
for header := self.chain.GetHeader(self.header.ParentHash, self.header.Number.Uint64()-1); header != nil; header = self.chain.GetHeader(header.ParentHash, header.Number.Uint64()-1) {
|
||||||
if header.Number.Uint64() == n {
|
if header.Number.Uint64() == n {
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ type Miner struct {
|
||||||
shouldStart int32 // should start indicates whether we should start after sync
|
shouldStart int32 // should start indicates whether we should start after sync
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(eth Backend, config *core.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
|
func New(eth Backend, config *params.ChainConfig, mux *event.TypeMux, pow pow.PoW) *Miner {
|
||||||
miner := &Miner{
|
miner := &Miner{
|
||||||
eth: eth,
|
eth: eth,
|
||||||
mux: mux,
|
mux: mux,
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,9 @@ type uint64RingBuffer struct {
|
||||||
// Work is the workers current environment and holds
|
// Work is the workers current environment and holds
|
||||||
// all of the current state information
|
// all of the current state information
|
||||||
type Work struct {
|
type Work struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
|
signer types.Signer
|
||||||
|
|
||||||
state *state.StateDB // apply state changes here
|
state *state.StateDB // apply state changes here
|
||||||
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
ancestors *set.Set // ancestor set (used for checking uncle parent validity)
|
||||||
family *set.Set // family set (used for checking uncle invalidity)
|
family *set.Set // family set (used for checking uncle invalidity)
|
||||||
|
|
@ -90,7 +92,7 @@ type Result struct {
|
||||||
|
|
||||||
// worker is the main object which takes care of applying messages to the new state
|
// worker is the main object which takes care of applying messages to the new state
|
||||||
type worker struct {
|
type worker struct {
|
||||||
config *core.ChainConfig
|
config *params.ChainConfig
|
||||||
|
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
|
|
||||||
|
|
@ -128,7 +130,7 @@ type worker struct {
|
||||||
fullValidation bool
|
fullValidation bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWorker(config *core.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
|
func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend, mux *event.TypeMux) *worker {
|
||||||
worker := &worker{
|
worker := &worker{
|
||||||
config: config,
|
config: config,
|
||||||
eth: eth,
|
eth: eth,
|
||||||
|
|
@ -235,7 +237,7 @@ func (self *worker) update() {
|
||||||
if atomic.LoadInt32(&self.mining) == 0 {
|
if atomic.LoadInt32(&self.mining) == 0 {
|
||||||
self.currentMu.Lock()
|
self.currentMu.Lock()
|
||||||
|
|
||||||
acc, _ := ev.Tx.From()
|
acc, _ := types.Sender(self.current.signer, ev.Tx)
|
||||||
txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}}
|
txs := map[common.Address]types.Transactions{acc: types.Transactions{ev.Tx}}
|
||||||
txset := types.NewTransactionsByPriceAndNonce(txs)
|
txset := types.NewTransactionsByPriceAndNonce(txs)
|
||||||
|
|
||||||
|
|
@ -276,7 +278,7 @@ func (self *worker) wait() {
|
||||||
}
|
}
|
||||||
go self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
go self.mux.Post(core.NewMinedBlockEvent{Block: block})
|
||||||
} else {
|
} else {
|
||||||
work.state.Commit()
|
work.state.Commit(self.config.IsEIP158(block.Number()))
|
||||||
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
parent := self.chain.GetBlock(block.ParentHash(), block.NumberU64()-1)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
glog.V(logger.Error).Infoln("Invalid block found during mining")
|
||||||
|
|
@ -367,6 +369,7 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
|
||||||
}
|
}
|
||||||
work := &Work{
|
work := &Work{
|
||||||
config: self.config,
|
config: self.config,
|
||||||
|
signer: types.NewEIP155Signer(self.config.ChainId),
|
||||||
state: state,
|
state: state,
|
||||||
ancestors: set.New(),
|
ancestors: set.New(),
|
||||||
family: set.New(),
|
family: set.New(),
|
||||||
|
|
@ -528,7 +531,7 @@ func (self *worker) commitNewWork() {
|
||||||
if atomic.LoadInt32(&self.mining) == 1 {
|
if atomic.LoadInt32(&self.mining) == 1 {
|
||||||
// commit state root after all state transitions.
|
// commit state root after all state transitions.
|
||||||
core.AccumulateRewards(work.state, header, uncles)
|
core.AccumulateRewards(work.state, header, uncles)
|
||||||
header.Root = work.state.IntermediateRoot()
|
header.Root = work.state.IntermediateRoot(self.config.IsEIP158(header.Number))
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the new block whose nonce will be mined.
|
// create the new block whose nonce will be mined.
|
||||||
|
|
@ -570,7 +573,17 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
|
||||||
}
|
}
|
||||||
// Error may be ignored here. The error has already been checked
|
// Error may be ignored here. The error has already been checked
|
||||||
// during transaction acceptance is the transaction pool.
|
// during transaction acceptance is the transaction pool.
|
||||||
from, _ := tx.From()
|
//
|
||||||
|
// We use the eip155 signer regardless of the current hf.
|
||||||
|
from, _ := types.Sender(env.signer, tx)
|
||||||
|
// Check whether the tx is replay protected. If we're not in the EIP155 hf
|
||||||
|
// phase, start ignoring the sender until we do.
|
||||||
|
if tx.Protected() && !env.config.IsEIP155(env.header.Number) {
|
||||||
|
glog.V(logger.Detail).Infof("Transaction (%x) is replay protected, but we haven't yet hardforked. Transaction will be ignored until we hardfork.\n", tx.Hash())
|
||||||
|
|
||||||
|
txs.Pop()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Ignore any transactions (and accounts subsequently) with low gas limits
|
// Ignore any transactions (and accounts subsequently) with low gas limits
|
||||||
if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
|
if tx.GasPrice().Cmp(gasPrice) < 0 && !env.ownedAccounts.Has(from) {
|
||||||
|
|
@ -620,14 +633,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
|
||||||
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
|
func (env *Work) commitTransaction(tx *types.Transaction, bc *core.BlockChain, gp *core.GasPool) (error, vm.Logs) {
|
||||||
snap := env.state.Snapshot()
|
snap := env.state.Snapshot()
|
||||||
|
|
||||||
// this is a bit of a hack to force jit for the miners
|
receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, vm.Config{})
|
||||||
config := env.config.VmConfig
|
|
||||||
if !(config.EnableJit && config.ForceJit) {
|
|
||||||
config.EnableJit = false
|
|
||||||
}
|
|
||||||
config.ForceJit = false // disable forcing jit
|
|
||||||
|
|
||||||
receipt, logs, _, err := core.ApplyTransaction(env.config, bc, gp, env.state, env.header, tx, env.header.GasUsed, config)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
env.state.RevertToSnapshot(snap)
|
env.state.RevertToSnapshot(snap)
|
||||||
return err, nil
|
return err, nil
|
||||||
|
|
|
||||||
181
mobile/accounts.go
Normal file
181
mobile/accounts.go
Normal file
|
|
@ -0,0 +1,181 @@
|
||||||
|
// Copyright 2016 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/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the accounts package to support client side key
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// StandardScryptN is the N parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
|
StandardScryptN = int(accounts.StandardScryptN)
|
||||||
|
|
||||||
|
// StandardScryptP is the P parameter of Scrypt encryption algorithm, using 256MB
|
||||||
|
// memory and taking approximately 1s CPU time on a modern processor.
|
||||||
|
StandardScryptP = int(accounts.StandardScryptP)
|
||||||
|
|
||||||
|
// LightScryptN is the N parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
|
LightScryptN = int(accounts.LightScryptN)
|
||||||
|
|
||||||
|
// LightScryptP is the P parameter of Scrypt encryption algorithm, using 4MB
|
||||||
|
// memory and taking approximately 100ms CPU time on a modern processor.
|
||||||
|
LightScryptP = int(accounts.LightScryptP)
|
||||||
|
)
|
||||||
|
|
||||||
|
// Account represents a stored key.
|
||||||
|
type Account struct{ account accounts.Account }
|
||||||
|
|
||||||
|
// Accounts represents a slice of accounts.
|
||||||
|
type Accounts struct{ accounts []accounts.Account }
|
||||||
|
|
||||||
|
// Size returns the number of accounts in the slice.
|
||||||
|
func (a *Accounts) Size() int {
|
||||||
|
return len(a.accounts)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the account at the given index from the slice.
|
||||||
|
func (a *Accounts) Get(index int) (*Account, error) {
|
||||||
|
if index < 0 || index >= len(a.accounts) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &Account{a.accounts[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the account at the given index in the slice.
|
||||||
|
func (a *Accounts) Set(index int, account *Account) error {
|
||||||
|
if index < 0 || index >= len(a.accounts) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
a.accounts[index] = account.account
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAddress retrieves the address associated with the account.
|
||||||
|
func (a *Account) GetAddress() *Address {
|
||||||
|
return &Address{a.account.Address}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetFile retrieves the path of the file containing the account key.
|
||||||
|
func (a *Account) GetFile() string {
|
||||||
|
return a.account.File
|
||||||
|
}
|
||||||
|
|
||||||
|
// AccountManager manages a key storage directory on disk.
|
||||||
|
type AccountManager struct{ manager *accounts.Manager }
|
||||||
|
|
||||||
|
// NewAccountManager creates a manager for the given directory.
|
||||||
|
func NewAccountManager(keydir string, scryptN, scryptP int) *AccountManager {
|
||||||
|
return &AccountManager{manager: accounts.NewManager(keydir, scryptN, scryptP)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HasAddress reports whether a key with the given address is present.
|
||||||
|
func (am *AccountManager) HasAddress(addr *Address) bool {
|
||||||
|
return am.manager.HasAddress(addr.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAccounts returns all key files present in the directory.
|
||||||
|
func (am *AccountManager) GetAccounts() *Accounts {
|
||||||
|
return &Accounts{am.manager.Accounts()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteAccount deletes the key matched by account if the passphrase is correct.
|
||||||
|
// If a contains no filename, the address must match a unique key.
|
||||||
|
func (am *AccountManager) DeleteAccount(a *Account, passphrase string) error {
|
||||||
|
return am.manager.DeleteAccount(accounts.Account{
|
||||||
|
Address: a.account.Address,
|
||||||
|
File: a.account.File,
|
||||||
|
}, passphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sign signs hash with an unlocked private key matching the given address.
|
||||||
|
func (am *AccountManager) Sign(addr *Address, hash []byte) ([]byte, error) {
|
||||||
|
return am.manager.Sign(addr.address, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignWithPassphrase signs hash if the private key matching the given address can be
|
||||||
|
// decrypted with the given passphrase.
|
||||||
|
func (am *AccountManager) SignWithPassphrase(addr *Address, passphrase string, hash []byte) ([]byte, error) {
|
||||||
|
return am.manager.SignWithPassphrase(addr.address, passphrase, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlock unlocks the given account indefinitely.
|
||||||
|
func (am *AccountManager) Unlock(a *Account, passphrase string) error {
|
||||||
|
return am.manager.TimedUnlock(a.account, passphrase, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lock removes the private key with the given address from memory.
|
||||||
|
func (am *AccountManager) Lock(addr *Address) error {
|
||||||
|
return am.manager.Lock(addr.address)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TimedUnlock unlocks the given account with the passphrase. The account
|
||||||
|
// stays unlocked for the duration of timeout. A timeout of 0 unlocks the account
|
||||||
|
// until the program exits. The account must match a unique key file.
|
||||||
|
//
|
||||||
|
// If the account address is already unlocked for a duration, TimedUnlock extends or
|
||||||
|
// shortens the active unlock timeout. If the address was previously unlocked
|
||||||
|
// indefinitely the timeout is not altered.
|
||||||
|
func (am *AccountManager) TimedUnlock(a *Account, passphrase string, timeout int64) error {
|
||||||
|
return am.manager.TimedUnlock(a.account, passphrase, time.Duration(timeout))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAccount generates a new key and stores it into the key directory,
|
||||||
|
// encrypting it with the passphrase.
|
||||||
|
func (am *AccountManager) NewAccount(passphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.NewAccount(passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExportKey exports as a JSON key, encrypted with newPassphrase.
|
||||||
|
func (am *AccountManager) ExportKey(a *Account, passphrase, newPassphrase string) ([]byte, error) {
|
||||||
|
return am.manager.Export(a.account, passphrase, newPassphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportKey stores the given encrypted JSON key into the key directory.
|
||||||
|
func (am *AccountManager) ImportKey(keyJSON []byte, passphrase, newPassphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.Import(keyJSON, passphrase, newPassphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update changes the passphrase of an existing account.
|
||||||
|
func (am *AccountManager) Update(a *Account, passphrase, newPassphrase string) error {
|
||||||
|
return am.manager.Update(a.account, passphrase, newPassphrase)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ImportPreSaleKey decrypts the given Ethereum presale wallet and stores
|
||||||
|
// a key file in the key directory. The key file is encrypted with the same passphrase.
|
||||||
|
func (am *AccountManager) ImportPreSaleKey(keyJSON []byte, passphrase string) (*Account, error) {
|
||||||
|
account, err := am.manager.ImportPreSaleKey(keyJSON, passphrase)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Account{account}, nil
|
||||||
|
}
|
||||||
203
mobile/android_test.go
Normal file
203
mobile/android_test.go
Normal file
|
|
@ -0,0 +1,203 @@
|
||||||
|
// Copyright 2016 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/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the accounts package to support client side key
|
||||||
|
// management on mobile platforms.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/internal/build"
|
||||||
|
)
|
||||||
|
|
||||||
|
// androidTestClass is a Java class to do some lightweight tests against the Android
|
||||||
|
// bindings. The goal is not to test each individual functionality, rather just to
|
||||||
|
// catch breaking API and/or implementation changes.
|
||||||
|
const androidTestClass = `
|
||||||
|
package go;
|
||||||
|
|
||||||
|
import android.test.InstrumentationTestCase;
|
||||||
|
import android.test.MoreAsserts;
|
||||||
|
|
||||||
|
import org.ethereum.geth.*;
|
||||||
|
|
||||||
|
public class AndroidTest extends InstrumentationTestCase {
|
||||||
|
public AndroidTest() {}
|
||||||
|
|
||||||
|
public void testAccountManagement() {
|
||||||
|
try {
|
||||||
|
AccountManager am = new AccountManager(getInstrumentation().getContext().getFilesDir() + "/keystore", Geth.LightScryptN, Geth.LightScryptP);
|
||||||
|
|
||||||
|
Account newAcc = am.newAccount("Creation password");
|
||||||
|
byte[] jsonAcc = am.exportKey(newAcc, "Creation password", "Export password");
|
||||||
|
|
||||||
|
am.deleteAccount(newAcc, "Creation password");
|
||||||
|
Account impAcc = am.importKey(jsonAcc, "Export password", "Import password");
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testInprocNode() {
|
||||||
|
Context ctx = new Context();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Start up a new inprocess node
|
||||||
|
Node node = new Node(getInstrumentation().getContext().getFilesDir() + "/.ethereum", new NodeConfig());
|
||||||
|
node.start();
|
||||||
|
|
||||||
|
// Retrieve some data via function calls (we don't really care about the results)
|
||||||
|
NodeInfo info = node.getNodeInfo();
|
||||||
|
info.getName();
|
||||||
|
info.getListenerAddress();
|
||||||
|
info.getProtocols();
|
||||||
|
|
||||||
|
// Retrieve some data via the APIs (we don't really care about the results)
|
||||||
|
EthereumClient ec = node.getEthereumClient();
|
||||||
|
ec.getBlockByNumber(ctx, -1).getNumber();
|
||||||
|
|
||||||
|
NewHeadHandler handler = new NewHeadHandler() {
|
||||||
|
@Override public void onError(String error) {}
|
||||||
|
@Override public void onNewHead(final Header header) {}
|
||||||
|
};
|
||||||
|
ec.subscribeNewHead(ctx, handler, 16);
|
||||||
|
} catch (Exception e) {
|
||||||
|
fail(e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestAndroid runs the Android java test class specified above.
|
||||||
|
//
|
||||||
|
// This requires the gradle command in PATH and the Android SDK whose path is available
|
||||||
|
// through ANDROID_HOME environment variable. To successfully run the tests, an Android
|
||||||
|
// device must also be available with debugging enabled.
|
||||||
|
//
|
||||||
|
// This method has been adapted from golang.org/x/mobile/bind/java/seq_test.go/runTest
|
||||||
|
func TestAndroid(t *testing.T) {
|
||||||
|
// Skip tests on Windows altogether
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
t.Skip("cannot test Android bindings on Windows, skipping")
|
||||||
|
}
|
||||||
|
// Make sure all the Android tools are installed
|
||||||
|
if _, err := exec.Command("which", "gradle").CombinedOutput(); err != nil {
|
||||||
|
t.Skip("command gradle not found, skipping")
|
||||||
|
}
|
||||||
|
if sdk := os.Getenv("ANDROID_HOME"); sdk == "" {
|
||||||
|
t.Skip("ANDROID_HOME environment var not set, skipping")
|
||||||
|
}
|
||||||
|
if _, err := exec.Command("which", "gomobile").CombinedOutput(); err != nil {
|
||||||
|
t.Log("gomobile missing, installing it...")
|
||||||
|
if _, err := exec.Command("go", "install", "golang.org/x/mobile/cmd/gomobile").CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("install failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Log("initializing gomobile...")
|
||||||
|
start := time.Now()
|
||||||
|
if _, err := exec.Command("gomobile", "init").CombinedOutput(); err != nil {
|
||||||
|
t.Fatalf("initialization failed: %v", err)
|
||||||
|
}
|
||||||
|
t.Logf("initialization took %v", time.Since(start))
|
||||||
|
}
|
||||||
|
// Create and switch to a temporary workspace
|
||||||
|
workspace, err := ioutil.TempDir("", "geth-android-")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to create temporary workspace: %v", err)
|
||||||
|
}
|
||||||
|
defer os.RemoveAll(workspace)
|
||||||
|
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to get current working directory: %v", err)
|
||||||
|
}
|
||||||
|
if err := os.Chdir(workspace); err != nil {
|
||||||
|
t.Fatalf("failed to switch to temporary workspace: %v", err)
|
||||||
|
}
|
||||||
|
defer os.Chdir(pwd)
|
||||||
|
|
||||||
|
// Create the skeleton of the Android project
|
||||||
|
for _, dir := range []string{"src/main", "src/androidTest/java/org/ethereum/gethtest", "libs"} {
|
||||||
|
err = os.MkdirAll(dir, os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Generate the mobile bindings for Geth and add the tester class
|
||||||
|
gobind := exec.Command("gomobile", "bind", "-javapkg", "org.ethereum", "github.com/ethereum/go-ethereum/mobile")
|
||||||
|
if output, err := gobind.CombinedOutput(); err != nil {
|
||||||
|
t.Logf("%s", output)
|
||||||
|
t.Fatalf("failed to run gomobile bind: %v", err)
|
||||||
|
}
|
||||||
|
build.CopyFile(filepath.Join("libs", "geth.aar"), "geth.aar", os.ModePerm)
|
||||||
|
|
||||||
|
if err = ioutil.WriteFile(filepath.Join("src", "androidTest", "java", "org", "ethereum", "gethtest", "AndroidTest.java"), []byte(androidTestClass), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write Android test class: %v", err)
|
||||||
|
}
|
||||||
|
// Finish creating the project and run the tests via gradle
|
||||||
|
if err = ioutil.WriteFile(filepath.Join("src", "main", "AndroidManifest.xml"), []byte(androidManifest), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write Android manifest: %v", err)
|
||||||
|
}
|
||||||
|
if err = ioutil.WriteFile("build.gradle", []byte(gradleConfig), os.ModePerm); err != nil {
|
||||||
|
t.Fatalf("failed to write gradle build file: %v", err)
|
||||||
|
}
|
||||||
|
if output, err := exec.Command("gradle", "connectedAndroidTest").CombinedOutput(); err != nil {
|
||||||
|
t.Logf("%s", output)
|
||||||
|
t.Errorf("failed to run gradle test: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const androidManifest = `<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="org.ethereum.gethtest"
|
||||||
|
android:versionCode="1"
|
||||||
|
android:versionName="1.0">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</manifest>`
|
||||||
|
|
||||||
|
const gradleConfig = `buildscript {
|
||||||
|
repositories {
|
||||||
|
jcenter()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:1.5.0'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
allprojects {
|
||||||
|
repositories { jcenter() }
|
||||||
|
}
|
||||||
|
apply plugin: 'com.android.library'
|
||||||
|
android {
|
||||||
|
compileSdkVersion 'android-19'
|
||||||
|
buildToolsVersion '21.1.2'
|
||||||
|
defaultConfig { minSdkVersion 15 }
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
flatDir { dirs 'libs' }
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
compile 'com.android.support:appcompat-v7:19.0.0'
|
||||||
|
compile(name: "geth", ext: "aar")
|
||||||
|
}
|
||||||
|
`
|
||||||
95
mobile/big.go
Normal file
95
mobile/big.go
Normal file
|
|
@ -0,0 +1,95 @@
|
||||||
|
// Copyright 2016 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/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the math/big package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math/big"
|
||||||
|
)
|
||||||
|
|
||||||
|
// A BigInt represents a signed multi-precision integer.
|
||||||
|
type BigInt struct {
|
||||||
|
bigint *big.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBigInt allocates and returns a new BigInt set to x.
|
||||||
|
func NewBigInt(x int64) *BigInt {
|
||||||
|
return &BigInt{big.NewInt(x)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBytes returns the absolute value of x as a big-endian byte slice.
|
||||||
|
func (bi *BigInt) GetBytes() []byte {
|
||||||
|
return bi.bigint.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the value of x as a formatted decimal string.
|
||||||
|
func (bi *BigInt) String() string {
|
||||||
|
return bi.bigint.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInt64 returns the int64 representation of x. If x cannot be represented in
|
||||||
|
// an int64, the result is undefined.
|
||||||
|
func (bi *BigInt) GetInt64() int64 {
|
||||||
|
return bi.bigint.Int64()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetBytes interprets buf as the bytes of a big-endian unsigned integer and sets
|
||||||
|
// the big int to that value.
|
||||||
|
func (bi *BigInt) SetBytes(buf []byte) {
|
||||||
|
bi.bigint.SetBytes(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetInt64 sets the big int to x.
|
||||||
|
func (bi *BigInt) SetInt64(x int64) {
|
||||||
|
bi.bigint.SetInt64(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetString sets the big int to x.
|
||||||
|
//
|
||||||
|
// The string prefix determines the actual conversion base. A prefix of "0x" or
|
||||||
|
// "0X" selects base 16; the "0" prefix selects base 8, and a "0b" or "0B" prefix
|
||||||
|
// selects base 2. Otherwise the selected base is 10.
|
||||||
|
func (bi *BigInt) SetString(x string, base int) {
|
||||||
|
bi.bigint.SetString(x, base)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BigInts represents a slice of big ints.
|
||||||
|
type BigInts struct{ bigints []*big.Int }
|
||||||
|
|
||||||
|
// Size returns the number of big ints in the slice.
|
||||||
|
func (bi *BigInts) Size() int {
|
||||||
|
return len(bi.bigints)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns the bigint at the given index from the slice.
|
||||||
|
func (bi *BigInts) Get(index int) (*BigInt, error) {
|
||||||
|
if index < 0 || index >= len(bi.bigints) {
|
||||||
|
return nil, errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
return &BigInt{bi.bigints[index]}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the big int at the given index in the slice.
|
||||||
|
func (bi *BigInts) Set(index int, bigint *BigInt) error {
|
||||||
|
if index < 0 || index >= len(bi.bigints) {
|
||||||
|
return errors.New("index out of bounds")
|
||||||
|
}
|
||||||
|
bi.bigints[index] = bigint.bigint
|
||||||
|
return nil
|
||||||
|
}
|
||||||
26
mobile/big_go1.7.go
Normal file
26
mobile/big_go1.7.go
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2016 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/>.
|
||||||
|
|
||||||
|
// Contains the wrappers from the math/big package that require Go 1.7 and above.
|
||||||
|
|
||||||
|
// +build go1.7
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
// GetString returns the value of x as a formatted string in some number base.
|
||||||
|
func (bi *BigInt) GetString(base int) string {
|
||||||
|
return bi.bigint.Text(base)
|
||||||
|
}
|
||||||
202
mobile/bind.go
Normal file
202
mobile/bind.go
Normal file
|
|
@ -0,0 +1,202 @@
|
||||||
|
// Copyright 2016 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/>.
|
||||||
|
|
||||||
|
// Contains all the wrappers from the bind package.
|
||||||
|
|
||||||
|
package geth
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Signer is an interaface defining the callback when a contract requires a
|
||||||
|
// method to sign the transaction before submission.
|
||||||
|
type Signer interface {
|
||||||
|
Sign(*Address, *Transaction) (*Transaction, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type signer struct {
|
||||||
|
sign bind.SignerFn
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *signer) Sign(addr *Address, tx *Transaction) (*Transaction, error) {
|
||||||
|
sig, err := s.sign(types.HomesteadSigner{}, addr.address, tx.tx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{sig}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CallOpts is the collection of options to fine tune a contract call request.
|
||||||
|
type CallOpts struct {
|
||||||
|
opts bind.CallOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCallOpts creates a new option set for contract calls.
|
||||||
|
func NewCallOpts() *CallOpts {
|
||||||
|
return new(CallOpts)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *CallOpts) IsPending() bool { return opts.opts.Pending }
|
||||||
|
func (opts *CallOpts) GetGasLimit() int64 { return 0 /* TODO(karalabe) */ }
|
||||||
|
|
||||||
|
// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// Even then it's awkward to unpack the subtleties of a Go context out to Java.
|
||||||
|
// func (opts *CallOpts) GetContext() *Context { return &Context{opts.opts.Context} }
|
||||||
|
|
||||||
|
func (opts *CallOpts) SetPending(pending bool) { opts.opts.Pending = pending }
|
||||||
|
func (opts *CallOpts) SetGasLimit(limit int64) { /* TODO(karalabe) */ }
|
||||||
|
func (opts *CallOpts) SetContext(context *Context) { opts.opts.Context = context.context }
|
||||||
|
|
||||||
|
// TransactOpts is the collection of authorization data required to create a
|
||||||
|
// valid Ethereum transaction.
|
||||||
|
type TransactOpts struct {
|
||||||
|
opts bind.TransactOpts
|
||||||
|
}
|
||||||
|
|
||||||
|
func (opts *TransactOpts) GetFrom() *Address { return &Address{opts.opts.From} }
|
||||||
|
func (opts *TransactOpts) GetNonce() int64 { return opts.opts.Nonce.Int64() }
|
||||||
|
func (opts *TransactOpts) GetValue() *BigInt { return &BigInt{opts.opts.Value} }
|
||||||
|
func (opts *TransactOpts) GetGasPrice() *BigInt { return &BigInt{opts.opts.GasPrice} }
|
||||||
|
func (opts *TransactOpts) GetGasLimit() int64 { return opts.opts.GasLimit.Int64() }
|
||||||
|
|
||||||
|
// GetSigner cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// func (opts *TransactOpts) GetSigner() Signer { return &signer{opts.opts.Signer} }
|
||||||
|
|
||||||
|
// GetContext cannot be reliably implemented without identity preservation (https://github.com/golang/go/issues/16876)
|
||||||
|
// Even then it's awkward to unpack the subtleties of a Go context out to Java.
|
||||||
|
//func (opts *TransactOpts) GetContext() *Context { return &Context{opts.opts.Context} }
|
||||||
|
|
||||||
|
func (opts *TransactOpts) SetFrom(from *Address) { opts.opts.From = from.address }
|
||||||
|
func (opts *TransactOpts) SetNonce(nonce int64) { opts.opts.Nonce = big.NewInt(nonce) }
|
||||||
|
func (opts *TransactOpts) SetSigner(s Signer) {
|
||||||
|
opts.opts.Signer = func(signer types.Signer, addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
|
sig, err := s.Sign(&Address{addr}, &Transaction{tx})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return sig.tx, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func (opts *TransactOpts) SetValue(value *BigInt) { opts.opts.Value = value.bigint }
|
||||||
|
func (opts *TransactOpts) SetGasPrice(price *BigInt) { opts.opts.GasPrice = price.bigint }
|
||||||
|
func (opts *TransactOpts) SetGasLimit(limit int64) { opts.opts.GasLimit = big.NewInt(limit) }
|
||||||
|
func (opts *TransactOpts) SetContext(context *Context) { opts.opts.Context = context.context }
|
||||||
|
|
||||||
|
// BoundContract is the base wrapper object that reflects a contract on the
|
||||||
|
// Ethereum network. It contains a collection of methods that are used by the
|
||||||
|
// higher level contract bindings to operate.
|
||||||
|
type BoundContract struct {
|
||||||
|
contract *bind.BoundContract
|
||||||
|
address common.Address
|
||||||
|
deployer *types.Transaction
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeployContract deploys a contract onto the Ethereum blockchain and binds the
|
||||||
|
// deployment address with a wrapper.
|
||||||
|
func DeployContract(opts *TransactOpts, abiJSON string, bytecode []byte, client *EthereumClient, args *Interfaces) (*BoundContract, error) {
|
||||||
|
// Convert all the deployment parameters to Go types
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
// Deploy the contract to the network
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(abiJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
addr, tx, bound, err := bind.DeployContract(&opts.opts, parsed, bytecode, client.client, params...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BoundContract{
|
||||||
|
contract: bound,
|
||||||
|
address: addr,
|
||||||
|
deployer: tx,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindContract creates a low level contract interface through which calls and
|
||||||
|
// transactions may be made through.
|
||||||
|
func BindContract(address *Address, abiJSON string, client *EthereumClient) (*BoundContract, error) {
|
||||||
|
parsed, err := abi.JSON(strings.NewReader(abiJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &BoundContract{
|
||||||
|
contract: bind.NewBoundContract(address.address, parsed, client.client, client.client),
|
||||||
|
address: address.address,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *BoundContract) GetAddress() *Address { return &Address{c.address} }
|
||||||
|
func (c *BoundContract) GetDeployer() *Transaction {
|
||||||
|
if c.deployer == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &Transaction{c.deployer}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call invokes the (constant) contract method with params as input values and
|
||||||
|
// sets the output to result.
|
||||||
|
func (c *BoundContract) Call(opts *CallOpts, out *Interfaces, method string, args *Interfaces) error {
|
||||||
|
// Convert all the input and output parameters to Go types
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
results := make([]interface{}, len(out.objects))
|
||||||
|
for i, obj := range out.objects {
|
||||||
|
results[i] = obj
|
||||||
|
}
|
||||||
|
// Execute the call to the contract and wrap any results
|
||||||
|
if err := c.contract.Call(&opts.opts, &results, method, params...); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
for i, res := range results {
|
||||||
|
out.objects[i] = res
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transact invokes the (paid) contract method with params as input values.
|
||||||
|
func (c *BoundContract) Transact(opts *TransactOpts, method string, args *Interfaces) (*Transaction, error) {
|
||||||
|
params := make([]interface{}, len(args.objects))
|
||||||
|
for i, obj := range args.objects {
|
||||||
|
params[i] = obj
|
||||||
|
}
|
||||||
|
tx, err := c.contract.Transact(&opts.opts, method, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{tx}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer initiates a plain transaction to move funds to the contract, calling
|
||||||
|
// its default method if one is available.
|
||||||
|
func (c *BoundContract) Transfer(opts *TransactOpts) (*Transaction, error) {
|
||||||
|
tx, err := c.contract.Transfer(&opts.opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &Transaction{tx}, nil
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue