From fd39e6b30af5d855dce23899394e6ef80a2c0a41 Mon Sep 17 00:00:00 2001 From: Determinant Date: Mon, 12 Aug 2019 16:27:52 -0400 Subject: ... --- coreth.go | 338 +++++++++++++++++++++++++--------------------- examples/payments/main.go | 61 ++++++--- miner/worker.go | 2 + 3 files changed, 224 insertions(+), 177 deletions(-) diff --git a/coreth.go b/coreth.go index 04b24c3..ec60ce6 100644 --- a/coreth.go +++ b/coreth.go @@ -6,6 +6,10 @@ import ( "time" "errors" "runtime" + "io" + "crypto/ecdsa" + "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/common" //"github.com/ethereum/go-ethereum/eth" @@ -15,10 +19,10 @@ import ( "github.com/ethereum/go-ethereum/core/state" "github.com/Determinant/coreth/miner" "github.com/Determinant/coreth/eth" - "github.com/ethereum/go-ethereum/rlp" - "github.com/ethereum/go-ethereum/rpc" - "github.com/Determinant/coreth/node" - "golang.org/x/crypto/sha3" + "github.com/ethereum/go-ethereum/rlp" + "github.com/ethereum/go-ethereum/rpc" + "github.com/Determinant/coreth/node" + "github.com/ethereum/go-ethereum/crypto" ) type Tx = types.Transaction @@ -35,75 +39,75 @@ type DummyEngine struct { } var ( - allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks + allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks ) var ( - errZeroBlockTime = errors.New("timestamp equals parent's") + errZeroBlockTime = errors.New("timestamp equals parent's") ) // modified from consensus.go func (self *DummyEngine) verifyHeader(chain consensus.ChainReader, header, parent *types.Header, uncle bool, seal bool) error { - // Ensure that the header's extra-data section is of a reasonable size - if uint64(len(header.Extra)) > params.MaximumExtraDataSize { - return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) - } - // Verify the header's timestamp - if !uncle { - if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) { - return consensus.ErrFutureBlock - } - } - if header.Time <= parent.Time { - return errZeroBlockTime - } - // Verify that the gas limit is <= 2^63-1 - cap := uint64(0x7fffffffffffffff) - if header.GasLimit > cap { - return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) - } - // Verify that the gasUsed is <= gasLimit - if header.GasUsed > header.GasLimit { - return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) - } - - // Verify that the gas limit remains within allowed bounds - diff := int64(parent.GasLimit) - int64(header.GasLimit) - if diff < 0 { - diff *= -1 - } - limit := parent.GasLimit / params.GasLimitBoundDivisor - - if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { - return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) - } - // Verify that the block number is parent's +1 - if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { - return consensus.ErrInvalidNumber - } - // Verify the engine specific seal securing the block - if seal { - if err := self.VerifySeal(chain, header); err != nil { - return err - } - } - return nil + // Ensure that the header's extra-data section is of a reasonable size + if uint64(len(header.Extra)) > params.MaximumExtraDataSize { + return fmt.Errorf("extra-data too long: %d > %d", len(header.Extra), params.MaximumExtraDataSize) + } + // Verify the header's timestamp + if !uncle { + if header.Time > uint64(time.Now().Add(allowedFutureBlockTime).Unix()) { + return consensus.ErrFutureBlock + } + } + if header.Time <= parent.Time { + return errZeroBlockTime + } + // Verify that the gas limit is <= 2^63-1 + cap := uint64(0x7fffffffffffffff) + if header.GasLimit > cap { + return fmt.Errorf("invalid gasLimit: have %v, max %v", header.GasLimit, cap) + } + // Verify that the gasUsed is <= gasLimit + if header.GasUsed > header.GasLimit { + return fmt.Errorf("invalid gasUsed: have %d, gasLimit %d", header.GasUsed, header.GasLimit) + } + + // Verify that the gas limit remains within allowed bounds + diff := int64(parent.GasLimit) - int64(header.GasLimit) + if diff < 0 { + diff *= -1 + } + limit := parent.GasLimit / params.GasLimitBoundDivisor + + if uint64(diff) >= limit || header.GasLimit < params.MinGasLimit { + return fmt.Errorf("invalid gas limit: have %d, want %d += %d", header.GasLimit, parent.GasLimit, limit) + } + // Verify that the block number is parent's +1 + if diff := new(big.Int).Sub(header.Number, parent.Number); diff.Cmp(big.NewInt(1)) != 0 { + return consensus.ErrInvalidNumber + } + // Verify the engine specific seal securing the block + if seal { + if err := self.VerifySeal(chain, header); err != nil { + return err + } + } + return nil } func (self *DummyEngine) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, seals []bool, index int) error { - var parent *types.Header - if index == 0 { - parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) - } else if headers[index-1].Hash() == headers[index].ParentHash { - parent = headers[index-1] - } - if parent == nil { - return consensus.ErrUnknownAncestor - } - if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil { - return nil // known block - } - return self.verifyHeader(chain, headers[index], parent, false, seals[index]) + var parent *types.Header + if index == 0 { + parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) + } else if headers[index-1].Hash() == headers[index].ParentHash { + parent = headers[index-1] + } + if parent == nil { + return consensus.ErrUnknownAncestor + } + if chain.GetHeader(headers[index].Hash(), headers[index].Number.Uint64()) != nil { + return nil // known block + } + return self.verifyHeader(chain, headers[index], parent, false, seals[index]) } func (self *DummyEngine) Author(header *types.Header) (common.Address, error) { @@ -112,70 +116,70 @@ func (self *DummyEngine) Author(header *types.Header) (common.Address, error) { } func (self *DummyEngine) VerifyHeader(chain consensus.ChainReader, header *types.Header, seal bool) error { - // Short circuit if the header is known, or it's parent not - number := header.Number.Uint64() - if chain.GetHeader(header.Hash(), number) != nil { - return nil - } - parent := chain.GetHeader(header.ParentHash, number-1) - if parent == nil { - return consensus.ErrUnknownAncestor - } - // Sanity checks passed, do a proper verification - return self.verifyHeader(chain, header, parent, false, seal) + // Short circuit if the header is known, or it's parent not + number := header.Number.Uint64() + if chain.GetHeader(header.Hash(), number) != nil { + return nil + } + parent := chain.GetHeader(header.ParentHash, number-1) + if parent == nil { + return consensus.ErrUnknownAncestor + } + // Sanity checks passed, do a proper verification + return self.verifyHeader(chain, header, parent, false, seal) } func (self *DummyEngine) VerifyHeaders(chain consensus.ChainReader, headers []*types.Header, seals []bool) (chan<- struct{}, <-chan error) { - // Spawn as many workers as allowed threads - workers := runtime.GOMAXPROCS(0) - if len(headers) < workers { - workers = len(headers) - } - - // Create a task channel and spawn the verifiers - var ( - inputs = make(chan int) - done = make(chan int, workers) - errors = make([]error, len(headers)) - abort = make(chan struct{}) - ) - for i := 0; i < workers; i++ { - go func() { - for index := range inputs { - errors[index] = self.verifyHeaderWorker(chain, headers, seals, index) - done <- index - } - }() - } - - errorsOut := make(chan error, len(headers)) - go func() { - defer close(inputs) - var ( - in, out = 0, 0 - checked = make([]bool, len(headers)) - inputs = inputs - ) - for { - select { - case inputs <- in: - if in++; in == len(headers) { - // Reached end of headers. Stop sending to workers. - inputs = nil - } - case index := <-done: - for checked[index] = true; checked[out]; out++ { - errorsOut <- errors[out] - if out == len(headers)-1 { - return - } - } - case <-abort: - return - } - } - }() - return abort, errorsOut + // Spawn as many workers as allowed threads + workers := runtime.GOMAXPROCS(0) + if len(headers) < workers { + workers = len(headers) + } + + // Create a task channel and spawn the verifiers + var ( + inputs = make(chan int) + done = make(chan int, workers) + errors = make([]error, len(headers)) + abort = make(chan struct{}) + ) + for i := 0; i < workers; i++ { + go func() { + for index := range inputs { + errors[index] = self.verifyHeaderWorker(chain, headers, seals, index) + done <- index + } + }() + } + + errorsOut := make(chan error, len(headers)) + go func() { + defer close(inputs) + var ( + in, out = 0, 0 + checked = make([]bool, len(headers)) + inputs = inputs + ) + for { + select { + case inputs <- in: + if in++; in == len(headers) { + // Reached end of headers. Stop sending to workers. + inputs = nil + } + case index := <-done: + for checked[index] = true; checked[out]; out++ { + errorsOut <- errors[out] + if out == len(headers)-1 { + return + } + } + case <-abort: + return + } + } + }() + return abort, errorsOut } func (self *DummyEngine) VerifyUncles(chain consensus.ChainReader, block *types.Block) error { @@ -187,53 +191,56 @@ func (self *DummyEngine) VerifySeal(chain consensus.ChainReader, header *types.H } func (self *DummyEngine) Prepare(chain consensus.ChainReader, header *types.Header) error { - header.Difficulty = new(big.Int).SetUint64(0) - return nil + header.Difficulty = big.NewInt(0) + return nil } func (self *DummyEngine) Finalize(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header) { - // commit the final state root - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) +uncles []*types.Header) { + // commit the final state root + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) } func (self *DummyEngine) FinalizeAndAssemble(chain consensus.ChainReader, header *types.Header, state *state.StateDB, txs []*types.Transaction, - uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { - // commit the final state root - header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) +uncles []*types.Header, receipts []*types.Receipt) (*types.Block, error) { + // commit the final state root + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) - // Header seems complete, assemble into a block and return - return types.NewBlock(header, txs, uncles, receipts), nil + // Header seems complete, assemble into a block and return + return types.NewBlock(header, txs, uncles, receipts), nil } func (self *DummyEngine) Seal(chain consensus.ChainReader, block *types.Block, results chan<- *types.Block, stop <-chan struct{}) error { + time.Sleep(1000 * time.Millisecond) + fmt.Printf("sealed %s\n", block.ParentHash().String()) + results <- block return nil } func (self *DummyEngine) SealHash(header *types.Header) (hash common.Hash) { - hasher := sha3.NewLegacyKeccak256() - - rlp.Encode(hasher, []interface{}{ - header.ParentHash, - header.UncleHash, - header.Coinbase, - header.Root, - header.TxHash, - header.ReceiptHash, - header.Bloom, - header.Difficulty, - header.Number, - header.GasLimit, - header.GasUsed, - header.Time, - header.Extra, - }) - hasher.Sum(hash[:0]) - return hash + hasher := sha3.NewLegacyKeccak256() + + rlp.Encode(hasher, []interface{}{ + header.ParentHash, + header.UncleHash, + header.Coinbase, + header.Root, + header.TxHash, + header.ReceiptHash, + header.Bloom, + header.Difficulty, + header.Number, + header.GasLimit, + header.GasUsed, + header.Time, + header.Extra, + }) + hasher.Sum(hash[:0]) + return hash } func (self *DummyEngine) CalcDifficulty(chain consensus.ChainReader, time uint64, parent *types.Header) *big.Int { - return new(big.Int).SetUint64(0) + return big.NewInt(0) } func (self *DummyEngine) APIs(chain consensus.ChainReader) []rpc.API { @@ -245,7 +252,7 @@ func (self *DummyEngine) Close() error { } func isLocalBlock(block *types.Block) bool { - return false + return false } func NewETHChain(config *eth.Config, chainConfig *params.ChainConfig, etherBase *common.Address) *ETHChain { @@ -288,3 +295,24 @@ func (self *ETHChain) AddRemoteTxs(txs []*types.Transaction) []error { func (self *ETHChain) AddLocalTxs(txs []*types.Transaction) []error { return self.backend.TxPool().AddLocals(txs) } + +type Key struct { + Address common.Address + PrivateKey *ecdsa.PrivateKey +} + +func NewKeyFromECDSA(privateKeyECDSA *ecdsa.PrivateKey) *Key { + key := &Key{ + Address: crypto.PubkeyToAddress(privateKeyECDSA.PublicKey), + PrivateKey: privateKeyECDSA, + } + return key +} + +func NewKey(rand io.Reader) (*Key, error) { + privateKeyECDSA, err := ecdsa.GenerateKey(crypto.S256(), rand) + if err != nil { + return nil, err + } + return NewKeyFromECDSA(privateKeyECDSA), nil +} diff --git a/examples/payments/main.go b/examples/payments/main.go index 24ba962..d5d10b4 100644 --- a/examples/payments/main.go +++ b/examples/payments/main.go @@ -1,43 +1,60 @@ package main import ( + //"time" + "os" + "os/signal" + "syscall" + "crypto/rand" "math/big" - "encoding/hex" + //"encoding/hex" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/common" + //"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core" "github.com/Determinant/coreth/eth" "github.com/Determinant/coreth" - "github.com/ethereum/go-ethereum/log" - "github.com/ethereum/go-ethereum/params" - "time" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/params" ) +func checkError(err error) { + if err != nil { panic(err) } +} + func main() { - log.Root().SetHandler(log.StdoutHandler) + log.Root().SetHandler(log.StderrHandler) config := eth.DefaultConfig - genAddr := common.Address{} + chainConfig := params.MainnetChainConfig + genBalance := big.NewInt(1000000000000000000) + genKey, _ := coreth.NewKey(rand.Reader) + config.Genesis = &core.Genesis{ Config: params.MainnetChainConfig, - Nonce: 66, - ExtraData: hexutil.MustDecode("0x11bbe8db4e347b4e8c937c1c8370e4b5ed33adb3db69cbdb7a38e1e50b1b82fa"), - GasLimit: 5000, + Nonce: 0, + ExtraData: hexutil.MustDecode("0x00"), + GasLimit: 100000000, Difficulty: big.NewInt(0), - Alloc: core.GenesisAlloc{genAddr: {Balance: genBalance }}, + Alloc: core.GenesisAlloc{ genKey.Address: { Balance: genBalance }}, } - chain := coreth.NewETHChain(&config, nil, nil) - to := common.Address{} - nouce := 0 - amount := big.NewInt(0) - gasLimit := 1000000000 - gasPrice := big.NewInt(0) - deployCode, _ := hex.DecodeString("608060405234801561001057600080fd5b50600760008190555060cc806100276000396000f3fe6080604052600436106039576000357c0100000000000000000000000000000000000000000000000000000000900480631003e2d214603e575b600080fd5b348015604957600080fd5b50607360048036036020811015605e57600080fd5b81019080803590602001909291905050506089565b6040518082815260200191505060405180910390f35b60008160005401600081905550600054905091905056fea165627a7a7230582075069a1c11ef20dd272178c92ff7d593d7ef9c39b1a63e85588f9e45be9fb6420029") - tx := types.NewTransaction(uint64(nouce), to, amount, uint64(gasLimit), gasPrice, deployCode) + + chainID := chainConfig.ChainID + nonce := uint64(0) + value := big.NewInt(1000000000000) + gasLimit := 21000 + gasPrice := big.NewInt(1000) + bob, err := coreth.NewKey(rand.Reader); checkError(err) + tx := types.NewTransaction(nonce, bob.Address, value, uint64(gasLimit), gasPrice, nil) + signedTx, err := types.SignTx(tx, types.NewEIP155Signer(chainID), genKey.PrivateKey); checkError(err) + + chain := coreth.NewETHChain(&config, chainConfig, nil) chain.Start() - //_ = tx - chain.AddLocalTxs([]*types.Transaction{tx}) - time.Sleep(10000 * time.Millisecond) + chain.AddLocalTxs([]*types.Transaction{signedTx}) + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + signal.Notify(c, os.Interrupt, syscall.SIGINT) + <-c chain.Stop() } diff --git a/miner/worker.go b/miner/worker.go index edfd3f9..f5357f3 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -28,6 +28,7 @@ import ( "sync" "sync/atomic" "time" + "fmt" mapset "github.com/deckarep/golang-set" "github.com/ethereum/go-ethereum/common" @@ -617,6 +618,7 @@ func (w *worker) resultLoop() { // Insert the block into the set of pending ones to resultLoop for confirmations w.unconfirmed.Insert(block.NumberU64(), block.Hash()) + fmt.Printf("new parent: %s\n", w.chain.CurrentBlock().Hash().String()) case <-w.exitCh: return -- cgit v1.2.3