Ingest Block Batches (#8)
Handling BlockBatches in Geth at `SendBlockBatches` endpoint (eth_sendBlockBatches) Other: * Adding PR template * Adding ability to set timestamp and making blocks use configured timestamp * Adding ability to encode original tx nonce in calldata * Adding L1MessageSender to Contract Creation Txs
This commit is contained in:
parent
0a67cf87f3
commit
83c7d841eb
109
.github/CONTRIBUTING.md
vendored
109
.github/CONTRIBUTING.md
vendored
@ -1,40 +1,89 @@
|
|||||||
# Contributing
|
# Contributing
|
||||||
|
|
||||||
Thank you for considering to help out with the source code! We welcome
|
When contributing to this repository, please first discuss the change you wish to make via issue,
|
||||||
contributions from anyone on the internet, and are grateful for even the
|
email, or any other method with the owners of this repository before making a change.
|
||||||
smallest of fixes!
|
|
||||||
|
|
||||||
If you'd like to contribute to go-ethereum, please fork, fix, commit and send a
|
Please note we have a code of conduct, please follow it in all your interactions with the project.
|
||||||
pull request for the maintainers to review and merge into the main code base. If
|
|
||||||
you wish to submit more complex changes though, please check up with the core
|
|
||||||
devs first on [our gitter channel](https://gitter.im/ethereum/go-ethereum) to
|
|
||||||
ensure those changes are in line with the general philosophy of the project
|
|
||||||
and/or get some early feedback which can make both your efforts much lighter as
|
|
||||||
well as our review and merge procedures quick and simple.
|
|
||||||
|
|
||||||
## Coding guidelines
|
## Pull Request Process
|
||||||
|
|
||||||
Please make sure your contributions adhere to our coding guidelines:
|
1. Ensure that tests pass and code is lint free: `make all && make test && make lint`
|
||||||
|
2. Update the README.md if any changes invalidate its current content.
|
||||||
|
3. Include any tests for new functionality.
|
||||||
|
4. Reference any relevant issues in your PR comment.
|
||||||
|
|
||||||
* Code must adhere to the official Go
|
## Code of Conduct
|
||||||
[formatting](https://golang.org/doc/effective_go.html#formatting) guidelines
|
|
||||||
(i.e. uses [gofmt](https://golang.org/cmd/gofmt/)).
|
|
||||||
* Code must be documented adhering to the official Go
|
|
||||||
[commentary](https://golang.org/doc/effective_go.html#commentary) guidelines.
|
|
||||||
* Pull requests need to be based on and opened against the `master` branch.
|
|
||||||
* Commit messages should be prefixed with the package(s) they modify.
|
|
||||||
* E.g. "eth, rpc: make trace configs optional"
|
|
||||||
|
|
||||||
## Can I have feature X
|
### Our Pledge
|
||||||
|
|
||||||
Before you submit a feature request, please check and make sure that it isn't
|
In the interest of fostering an open and welcoming environment, we as
|
||||||
possible through some other means. The JavaScript-enabled console is a powerful
|
contributors and maintainers pledge to making participation in our project and
|
||||||
feature in the right hands. Please check our
|
our community a harassment-free experience for everyone, regardless of age, body
|
||||||
[Wiki page](https://github.com/ethereum/go-ethereum/wiki) for more info
|
size, disability, ethnicity, gender identity and expression, level of experience,
|
||||||
and help.
|
nationality, personal appearance, race, religion, or sexual identity and
|
||||||
|
orientation.
|
||||||
|
|
||||||
## Configuration, dependencies, and tests
|
### Our Standards
|
||||||
|
|
||||||
Please see the [Developers' Guide](https://github.com/ethereum/go-ethereum/wiki/Developers'-Guide)
|
Examples of behavior that contributes to creating a positive environment
|
||||||
for more details on configuring your environment, managing project dependencies
|
include:
|
||||||
and testing procedures.
|
|
||||||
|
* Using welcoming and inclusive language
|
||||||
|
* Being respectful of differing viewpoints and experiences
|
||||||
|
* Gracefully accepting constructive criticism
|
||||||
|
* Focusing on what is best for the community
|
||||||
|
* Showing empathy towards other community members
|
||||||
|
|
||||||
|
Examples of unacceptable behavior by participants include:
|
||||||
|
|
||||||
|
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||||
|
advances
|
||||||
|
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||||
|
* Public or private harassment
|
||||||
|
* Publishing others' private information, such as a physical or electronic
|
||||||
|
address, without explicit permission
|
||||||
|
* Other conduct which could reasonably be considered inappropriate in a
|
||||||
|
professional setting
|
||||||
|
|
||||||
|
### Our Responsibilities
|
||||||
|
|
||||||
|
Project maintainers are responsible for clarifying the standards of acceptable
|
||||||
|
behavior and are expected to take appropriate and fair corrective action in
|
||||||
|
response to any instances of unacceptable behavior.
|
||||||
|
|
||||||
|
Project maintainers have the right and responsibility to remove, edit, or
|
||||||
|
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||||
|
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||||
|
permanently any contributor for other behaviors that they deem inappropriate,
|
||||||
|
threatening, offensive, or harmful.
|
||||||
|
|
||||||
|
### Scope
|
||||||
|
|
||||||
|
This Code of Conduct applies both within project spaces and in public spaces
|
||||||
|
when an individual is representing the project or its community. Examples of
|
||||||
|
representing a project or community include using an official project e-mail
|
||||||
|
address, posting via an official social media account, or acting as an appointed
|
||||||
|
representative at an online or offline event. Representation of a project may be
|
||||||
|
further defined and clarified by project maintainers.
|
||||||
|
|
||||||
|
### Enforcement
|
||||||
|
|
||||||
|
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||||
|
reported by contacting the project team at contributing@optimism.io. All
|
||||||
|
complaints will be reviewed and investigated and will result in a response that
|
||||||
|
is deemed necessary and appropriate to the circumstances. The project team is
|
||||||
|
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||||
|
Further details of specific enforcement policies may be posted separately.
|
||||||
|
|
||||||
|
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||||
|
faith may face temporary or permanent repercussions as determined by other
|
||||||
|
members of the project's leadership.
|
||||||
|
|
||||||
|
### Attribution
|
||||||
|
|
||||||
|
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||||
|
available at [http://contributor-covenant.org/version/1/4][version] and from the [Angular Seed Contributing Guide][angular-contrib].
|
||||||
|
|
||||||
|
[homepage]: http://contributor-covenant.org
|
||||||
|
[version]: http://contributor-covenant.org/version/1/4/
|
||||||
|
[angular-contrib]: https://github.com/mgechev/angular-seed/blob/master/.github/CONTRIBUTING.md
|
||||||
|
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
## Description
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
-
|
||||||
|
-
|
||||||
|
-
|
||||||
|
|
||||||
|
## Metadata
|
||||||
|
### Fixes
|
||||||
|
- Fixes # [Link to Issue]
|
||||||
|
|
||||||
|
## Contributing Agreement
|
||||||
|
<!--
|
||||||
|
You *must* read and fully understand our Contributing Guide and Code of Conduct before submitting this pull request. Strong, healthy, and respectful communities are the best way to build great code 💖.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] I have read and understood the [Optimism Contributing Guide and Code of Conduct](./CONTRIBUTING.md) and am following those guidelines in this pull request.
|
@ -58,7 +58,7 @@ func TestSimulatedBackend(t *testing.T) {
|
|||||||
// generate a transaction and confirm you can retrieve it
|
// generate a transaction and confirm you can retrieve it
|
||||||
code := `6060604052600a8060106000396000f360606040526008565b00`
|
code := `6060604052600a8060106000396000f360606040526008565b00`
|
||||||
var gas uint64 = 3000000
|
var gas uint64 = 3000000
|
||||||
tx := types.NewContractCreation(0, big.NewInt(0), gas, big.NewInt(1), common.FromHex(code))
|
tx := types.NewContractCreation(0, big.NewInt(0), gas, big.NewInt(1), common.FromHex(code), nil)
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, key)
|
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, key)
|
||||||
|
|
||||||
err = sim.SendTransaction(context.Background(), tx)
|
err = sim.SendTransaction(context.Background(), tx)
|
||||||
|
@ -227,7 +227,7 @@ func (c *BoundContract) transact(opts *TransactOpts, contract *common.Address, i
|
|||||||
// Create the transaction, sign it and schedule it for execution
|
// Create the transaction, sign it and schedule it for execution
|
||||||
var rawTx *types.Transaction
|
var rawTx *types.Transaction
|
||||||
if contract == nil {
|
if contract == nil {
|
||||||
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input)
|
rawTx = types.NewContractCreation(nonce, value, gasLimit, gasPrice, input, nil)
|
||||||
} else {
|
} else {
|
||||||
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, nil)
|
rawTx = types.NewTransaction(nonce, c.address, value, gasLimit, gasPrice, input, nil)
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ func TestWaitDeployed(t *testing.T) {
|
|||||||
defer backend.Close()
|
defer backend.Close()
|
||||||
|
|
||||||
// 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), nil)
|
||||||
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
tx, _ = types.SignTx(tx, types.HomesteadSigner{}, testKey)
|
||||||
|
|
||||||
// Wait for it to get mined in the background.
|
// Wait for it to get mined in the background.
|
||||||
|
@ -254,7 +254,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
|
|||||||
return consensus.ErrFutureBlock
|
return consensus.ErrFutureBlock
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if header.Time <= parent.Time {
|
if header.Time < parent.Time {
|
||||||
return errOlderBlockTime
|
return errOlderBlockTime
|
||||||
}
|
}
|
||||||
// Verify the block's difficulty based on its timestamp and parent's difficulty
|
// Verify the block's difficulty based on its timestamp and parent's difficulty
|
||||||
|
@ -151,6 +151,8 @@ type BlockChain struct {
|
|||||||
|
|
||||||
chainmu sync.RWMutex // blockchain insertion lock
|
chainmu sync.RWMutex // blockchain insertion lock
|
||||||
|
|
||||||
|
currentTimestamp atomic.Value // Timestamp to be used when mining the current block.
|
||||||
|
|
||||||
currentBlock atomic.Value // Current head of the block chain
|
currentBlock atomic.Value // Current head of the block chain
|
||||||
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
currentFastBlock atomic.Value // Current head of the fast-sync chain (may be above the block chain!)
|
||||||
|
|
||||||
@ -234,6 +236,9 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
|
|||||||
bc.currentBlock.Store(nilBlock)
|
bc.currentBlock.Store(nilBlock)
|
||||||
bc.currentFastBlock.Store(nilBlock)
|
bc.currentFastBlock.Store(nilBlock)
|
||||||
|
|
||||||
|
// TODO: Make default current timestamp configurable & make 0 if genesis else load from last block?
|
||||||
|
bc.SetCurrentTimestamp(int64(0))
|
||||||
|
|
||||||
// Initialize the chain with ancient data if it isn't empty.
|
// Initialize the chain with ancient data if it isn't empty.
|
||||||
if bc.empty() {
|
if bc.empty() {
|
||||||
rawdb.InitDatabaseFromFreezer(bc.db)
|
rawdb.InitDatabaseFromFreezer(bc.db)
|
||||||
@ -495,6 +500,17 @@ func (bc *BlockChain) GasLimit() uint64 {
|
|||||||
return bc.CurrentBlock().GasLimit()
|
return bc.CurrentBlock().GasLimit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetCurrentTimestamp sets the timestamp for blocks added to the canonical chain.
|
||||||
|
func (bc *BlockChain) SetCurrentTimestamp(timestamp int64) {
|
||||||
|
bc.currentTimestamp.Store(×tamp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CurrentTimestamp retrieves the timestamp used for blocks added to the canonical chain.
|
||||||
|
func (bc *BlockChain) CurrentTimestamp() int64 {
|
||||||
|
// Note: Can never be nil
|
||||||
|
return *bc.currentTimestamp.Load().(*int64)
|
||||||
|
}
|
||||||
|
|
||||||
// CurrentBlock retrieves the current head block of the canonical chain. The
|
// CurrentBlock retrieves the current head block of the canonical chain. The
|
||||||
// block is retrieved from the blockchain's internal cache.
|
// block is retrieved from the blockchain's internal cache.
|
||||||
func (bc *BlockChain) CurrentBlock() *types.Block {
|
func (bc *BlockChain) CurrentBlock() *types.Block {
|
||||||
|
@ -949,7 +949,7 @@ func TestLogReorgs(t *testing.T) {
|
|||||||
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
|
blockchain.SubscribeRemovedLogsEvent(rmLogsCh)
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code, nil), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
@ -1042,7 +1042,7 @@ func TestLogRebirth(t *testing.T) {
|
|||||||
|
|
||||||
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
chain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code, nil), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
@ -1062,7 +1062,7 @@ func TestLogRebirth(t *testing.T) {
|
|||||||
// Generate long reorg chain
|
// Generate long reorg chain
|
||||||
forkChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
forkChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code, nil), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
@ -1162,7 +1162,7 @@ func TestSideLogRebirth(t *testing.T) {
|
|||||||
// Generate side chain with lower difficulty
|
// Generate side chain with lower difficulty
|
||||||
sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
sideChain, _ := GenerateChain(params.TestChainConfig, genesis, ethash.NewFaker(), db, 2, func(i int, gen *BlockGen) {
|
||||||
if i == 1 {
|
if i == 1 {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), code, nil), signer, key1)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to create tx: %v", err)
|
t.Fatalf("failed to create tx: %v", err)
|
||||||
}
|
}
|
||||||
@ -1207,7 +1207,7 @@ func TestReorgSideEvent(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) {
|
replacementBlocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, gen *BlockGen) {
|
||||||
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil), signer, key1)
|
tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), 1000000, new(big.Int), nil, nil), signer, key1)
|
||||||
if i == 2 {
|
if i == 2 {
|
||||||
gen.OffsetTime(-9)
|
gen.OffsetTime(-9)
|
||||||
}
|
}
|
||||||
|
@ -155,7 +155,7 @@ func encodeAsV3StoredReceiptRLP(want *Receipt) ([]byte, error) {
|
|||||||
func TestDeriveFields(t *testing.T) {
|
func TestDeriveFields(t *testing.T) {
|
||||||
// Create a few transactions to have receipts for
|
// Create a few transactions to have receipts for
|
||||||
txs := Transactions{
|
txs := Transactions{
|
||||||
NewContractCreation(1, big.NewInt(1), 1, big.NewInt(1), nil),
|
NewContractCreation(1, big.NewInt(1), 1, big.NewInt(1), nil, nil),
|
||||||
NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil),
|
NewTransaction(2, common.HexToAddress("0x2"), big.NewInt(2), 2, big.NewInt(2), nil, nil),
|
||||||
}
|
}
|
||||||
// Create the corresponding receipts
|
// Create the corresponding receipts
|
||||||
|
@ -19,6 +19,7 @@ package types
|
|||||||
import (
|
import (
|
||||||
"container/heap"
|
"container/heap"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
"math/big"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@ -76,8 +77,8 @@ func NewTransaction(nonce uint64, to common.Address, amount *big.Int, gasLimit u
|
|||||||
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data, l1MessageSender)
|
return newTransaction(nonce, &to, amount, gasLimit, gasPrice, data, l1MessageSender)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *Transaction {
|
func NewContractCreation(nonce uint64, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address) *Transaction {
|
||||||
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data, nil)
|
return newTransaction(nonce, nil, amount, gasLimit, gasPrice, data, l1MessageSender)
|
||||||
}
|
}
|
||||||
|
|
||||||
func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address) *Transaction {
|
func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte, l1MessageSender *common.Address) *Transaction {
|
||||||
@ -106,6 +107,29 @@ func newTransaction(nonce uint64, to *common.Address, amount *big.Int, gasLimit
|
|||||||
return &Transaction{data: d}
|
return &Transaction{data: d}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Appends the provided 64-bit nonce to this Transaction's calldata as the last 4 bytes
|
||||||
|
func (t *Transaction) AddNonceToWrappedTransaction(nonce uint64) {
|
||||||
|
bytes := make([]byte, 8)
|
||||||
|
for i := range bytes {
|
||||||
|
bytes[i] = 0xFF & byte(nonce>>(56-i))
|
||||||
|
}
|
||||||
|
t.data.Payload = append(t.data.Payload, bytes...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parses the encoded nonce from this Transaction's calldata and returns it as well as the calldata without the encoded nonce.
|
||||||
|
func (t *Transaction) GetNonceAndCalldataFromWrappedTransaction() (uint64, []byte, error) {
|
||||||
|
if len(t.data.Payload) < 8 {
|
||||||
|
return 0, nil, fmt.Errorf("Cannot parse encoded nonce out of calldata of less than 8 bytes in length. Calldata: %x", t.data.Payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
nonceBytes := t.data.Payload[len(t.data.Payload)-8:]
|
||||||
|
nonce := uint64(0)
|
||||||
|
for i := range nonceBytes {
|
||||||
|
nonce += uint64(nonceBytes[i] << (56 - i))
|
||||||
|
}
|
||||||
|
return nonce, t.data.Payload[:len(t.data.Payload)-8], nil
|
||||||
|
}
|
||||||
|
|
||||||
// ChainId returns which chain id this transaction was signed for (if at all)
|
// ChainId returns which chain id this transaction was signed for (if at all)
|
||||||
func (tx *Transaction) ChainId() *big.Int {
|
func (tx *Transaction) ChainId() *big.Int {
|
||||||
return deriveChainId(tx.data.V)
|
return deriveChainId(tx.data.V)
|
||||||
|
@ -190,7 +190,7 @@ func TestTransactionJSON(t *testing.T) {
|
|||||||
case 0:
|
case 0:
|
||||||
tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef"), &sender)
|
tx = NewTransaction(i, common.Address{1}, common.Big0, 1, common.Big2, []byte("abcdef"), &sender)
|
||||||
case 1:
|
case 1:
|
||||||
tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef"))
|
tx = NewContractCreation(i, common.Big0, 1, common.Big2, []byte("abcdef"), nil)
|
||||||
}
|
}
|
||||||
transactions = append(transactions, tx)
|
transactions = append(transactions, tx)
|
||||||
|
|
||||||
|
@ -60,6 +60,14 @@ func Sign(digestHash []byte, prv *ecdsa.PrivateKey) (sig []byte, err error) {
|
|||||||
return secp256k1.Sign(digestHash, seckey)
|
return secp256k1.Sign(digestHash, seckey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func VerifyMessageSignature(pubKey, unhashedMessage, signature []byte) bool {
|
||||||
|
if len(signature) < 64 || len(signature) > 65 {
|
||||||
|
// signature format may be [R || S] or [R || S || V]
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return VerifySignature(pubKey, Keccak256(unhashedMessage), signature[0:64])
|
||||||
|
}
|
||||||
|
|
||||||
// VerifySignature checks that the given public key created signature over digest.
|
// VerifySignature checks that the given public key created signature over digest.
|
||||||
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
// The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format.
|
||||||
// The signature should have the 64 byte [R || S] format.
|
// The signature should have the 64 byte [R || S] format.
|
||||||
|
@ -226,6 +226,14 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
|
|||||||
return b.eth.txPool.AddLocal(signedTx)
|
return b.eth.txPool.AddLocal(signedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthAPIBackend) SendTxs(ctx context.Context, signedTxs []*types.Transaction) []error {
|
||||||
|
return b.eth.txPool.AddLocals(signedTxs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *EthAPIBackend) SetTimestamp(timestamp int64) {
|
||||||
|
b.eth.blockchain.SetCurrentTimestamp(timestamp)
|
||||||
|
}
|
||||||
|
|
||||||
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
|
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
|
||||||
pending, err := b.eth.txPool.Pending()
|
pending, err := b.eth.txPool.Pending()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -19,6 +19,8 @@ package ethapi
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -1181,11 +1183,17 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa
|
|||||||
type PublicTransactionPoolAPI struct {
|
type PublicTransactionPoolAPI struct {
|
||||||
b Backend
|
b Backend
|
||||||
nonceLock *AddrLocker
|
nonceLock *AddrLocker
|
||||||
|
batchSigner *ecdsa.PrivateKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
// NewPublicTransactionPoolAPI creates a new RPC service with methods specific for the transaction pool.
|
||||||
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker) *PublicTransactionPoolAPI {
|
func NewPublicTransactionPoolAPI(b Backend, nonceLock *AddrLocker, batchSignerPrivKey *ecdsa.PrivateKey) *PublicTransactionPoolAPI {
|
||||||
return &PublicTransactionPoolAPI{b, nonceLock}
|
if batchSignerPrivKey == nil {
|
||||||
|
// should only be the case in unused code and some unit tests
|
||||||
|
key, _ := crypto.GenerateKey()
|
||||||
|
return &PublicTransactionPoolAPI{b, nonceLock, key}
|
||||||
|
}
|
||||||
|
return &PublicTransactionPoolAPI{b, nonceLock, batchSignerPrivKey}
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
// GetBlockTransactionCountByNumber returns the number of transactions in the block with the given block number.
|
||||||
@ -1440,11 +1448,40 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
|
|||||||
input = *args.Data
|
input = *args.Data
|
||||||
}
|
}
|
||||||
if args.To == nil {
|
if args.To == nil {
|
||||||
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input)
|
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, nil)
|
||||||
}
|
}
|
||||||
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, args.L1MessageSender)
|
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), uint64(*args.Gas), (*big.Int)(args.GasPrice), input, args.L1MessageSender)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RollupTransaction struct {
|
||||||
|
Nonce *hexutil.Uint64 `json:"nonce"`
|
||||||
|
GasLimit *hexutil.Uint64 `json:"gasLimit"`
|
||||||
|
Sender *common.Address `json:"sender"`
|
||||||
|
Target *common.Address `json:"target"`
|
||||||
|
Calldata *hexutil.Bytes `json:"calldata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Creates a wrapped tx (internal tx that wraps an OVM tx) from the RollupTransaction.
|
||||||
|
// The only part of the wrapped tx that has anything to do with the RollupTransaction is the calldata.
|
||||||
|
func (r *RollupTransaction) toTransaction(txNonce uint64) *types.Transaction {
|
||||||
|
var tx *types.Transaction
|
||||||
|
c, _ := r.Calldata.MarshalText()
|
||||||
|
if r.Target == nil {
|
||||||
|
tx = types.NewContractCreation(txNonce, big.NewInt(0), uint64(*r.GasLimit), big.NewInt(0), c, r.Sender)
|
||||||
|
} else {
|
||||||
|
tx = types.NewTransaction(txNonce, *r.Target, big.NewInt(0), uint64(*r.GasLimit), big.NewInt(0), c, r.Sender)
|
||||||
|
}
|
||||||
|
tx.AddNonceToWrappedTransaction(uint64(*r.Nonce))
|
||||||
|
return tx
|
||||||
|
}
|
||||||
|
|
||||||
|
// SendTxArgs represents the arguments to sumbit a new transaction into the transaction pool.
|
||||||
|
type BlockBatches struct {
|
||||||
|
Timestamp *hexutil.Uint64 `json:"timestamp"`
|
||||||
|
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
|
||||||
|
Batches [][]*RollupTransaction `json:"batches"`
|
||||||
|
}
|
||||||
|
|
||||||
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
|
// SubmitTransaction is a helper function that submits tx to txPool and logs a message.
|
||||||
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
|
func SubmitTransaction(ctx context.Context, b Backend, tx *types.Transaction) (common.Hash, error) {
|
||||||
if err := b.SendTx(ctx, tx); err != nil {
|
if err := b.SendTx(ctx, tx); err != nil {
|
||||||
@ -1522,6 +1559,55 @@ func (s *PublicTransactionPoolAPI) SendRawTransaction(ctx context.Context, encod
|
|||||||
return SubmitTransaction(ctx, s.b, tx)
|
return SubmitTransaction(ctx, s.b, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SendBlockBatches will:
|
||||||
|
// * Verify the batches are signed by the BlockBatchesSender
|
||||||
|
// * Update the Geth timestamp to the provided timestamp
|
||||||
|
// * handle the RollupTransaction Batches contained in the provided Block atomically
|
||||||
|
func (s *PublicTransactionPoolAPI) SendBlockBatches(ctx context.Context, messageAndSig []hexutil.Bytes) []error {
|
||||||
|
if len(messageAndSig) != 2 {
|
||||||
|
return []error{fmt.Errorf("incorrect number of arguments. Expected 2, got %d", len(messageAndSig))}
|
||||||
|
}
|
||||||
|
if !crypto.VerifyMessageSignature(crypto.FromECDSAPub(s.b.ChainConfig().BlockBatchesSender), messageAndSig[0], messageAndSig[1]) {
|
||||||
|
return []error{fmt.Errorf("signature does not match Block Batch Sender address %x", crypto.PubkeyToAddress(*s.b.ChainConfig().BlockBatchesSender))}
|
||||||
|
}
|
||||||
|
var blockBatches BlockBatches
|
||||||
|
if err := json.Unmarshal(messageAndSig[0], &blockBatches); err != nil {
|
||||||
|
return []error{fmt.Errorf("incorrect format for BlockBatches type. Received: %s", messageAndSig[0])}
|
||||||
|
}
|
||||||
|
|
||||||
|
txCount := 0
|
||||||
|
signer := types.MakeSigner(s.b.ChainConfig(), s.b.CurrentBlock().Number())
|
||||||
|
|
||||||
|
wrappedTxNonce, _ := s.b.GetPoolNonce(ctx, crypto.PubkeyToAddress(s.batchSigner.PublicKey))
|
||||||
|
signedBatches := make([][]*types.Transaction, len(blockBatches.Batches))
|
||||||
|
for bi, rollupTxs := range blockBatches.Batches {
|
||||||
|
signedBatches[bi] = make([]*types.Transaction, len(rollupTxs))
|
||||||
|
for i, rollupTx := range rollupTxs {
|
||||||
|
tx := rollupTx.toTransaction(wrappedTxNonce)
|
||||||
|
wrappedTxNonce++
|
||||||
|
tx, err := types.SignTx(tx, signer, s.batchSigner)
|
||||||
|
if err != nil {
|
||||||
|
return []error{fmt.Errorf("error signing transaction in batch %d, index %d", bi, i)}
|
||||||
|
}
|
||||||
|
signedBatches[bi][i] = tx
|
||||||
|
txCount++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.b.SetTimestamp(int64(*blockBatches.Timestamp))
|
||||||
|
|
||||||
|
i := 0
|
||||||
|
errs := make([]error, txCount)
|
||||||
|
for _, signedTxs := range signedBatches {
|
||||||
|
// TODO: Eventually make sure each batch is handled atomically
|
||||||
|
for _, e := range s.b.SendTxs(ctx, signedTxs) {
|
||||||
|
errs[i] = e
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
// Sign calculates an ECDSA signature for:
|
// Sign calculates an ECDSA signature for:
|
||||||
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
// keccack256("\x19Ethereum Signed Message:\n" + len(message) + message).
|
||||||
//
|
//
|
||||||
|
396
internal/ethapi/api_test.go
Normal file
396
internal/ethapi/api_test.go
Normal file
@ -0,0 +1,396 @@
|
|||||||
|
package ethapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/ecdsa"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/aws/aws-sdk-go/awstesting"
|
||||||
|
"github.com/ethereum/go-ethereum/accounts"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
"github.com/ethereum/go-ethereum/core"
|
||||||
|
"github.com/ethereum/go-ethereum/core/bloombits"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rpc"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
internalTxNonce = hexutil.Uint64(uint64(rand.Int()))
|
||||||
|
internalTxCalldata = hexutil.Bytes{0, 1, 2, 3, 4, 5, 6, 7}
|
||||||
|
internalTxSender = common.Address{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
|
||||||
|
internalTxTarget = common.Address{9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
|
||||||
|
backendTimestamp = int64(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
backendContext backendContext
|
||||||
|
inputCtx context.Context
|
||||||
|
inputMessageAndSig []hexutil.Bytes
|
||||||
|
hasErrors bool
|
||||||
|
resultingTimestamp int64
|
||||||
|
multipleBatches bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestCases(pk *ecdsa.PrivateKey) []testCase {
|
||||||
|
return []testCase{
|
||||||
|
// Bad input -- message and sig not of length 2
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: []hexutil.Bytes{}, hasErrors: true},
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: []hexutil.Bytes{[]byte{1, 2, 3}}, hasErrors: true},
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: []hexutil.Bytes{[]byte{1}, []byte{2}, []byte{3}}, hasErrors: true},
|
||||||
|
|
||||||
|
// Bad input -- message not signed
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: []hexutil.Bytes{[]byte{1}, []byte{2}}, hasErrors: true},
|
||||||
|
|
||||||
|
// Bad input -- message is signed but incorrect format
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getInputMessageAndSignature([]byte{1}, pk), hasErrors: true},
|
||||||
|
|
||||||
|
// Returns 0 errors if no transactions but timestamp updated
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 0, 1, []int{})},
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 1, []int{}), resultingTimestamp: 1},
|
||||||
|
|
||||||
|
// Handles one transaction and updates timestamp
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 1, []int{1}), resultingTimestamp: 1},
|
||||||
|
{backendContext: backendContext{sendTxsErrors: getDummyErrors([]int{0}, 1)}, inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 1, []int{1}), hasErrors: true, resultingTimestamp: 1},
|
||||||
|
|
||||||
|
// Handles one batch of multiple transaction and updates timestamp
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 1, []int{2}), resultingTimestamp: 1},
|
||||||
|
{backendContext: backendContext{sendTxsErrors: getDummyErrors([]int{1}, 2)}, inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 2, []int{2}), hasErrors: true, resultingTimestamp: 1},
|
||||||
|
|
||||||
|
// Handles multiple transactions and updates timestamp
|
||||||
|
{inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 2, 1, []int{1, 2, 3}), resultingTimestamp: 2},
|
||||||
|
{backendContext: backendContext{sendTxsErrors: getDummyErrors([]int{0, 2}, 3)}, inputCtx: getFakeContext(), inputMessageAndSig: getBlockBatchesInputMessageAndSignature(pk, 1, 1, []int{1, 2, 3}), hasErrors: true, resultingTimestamp: 1, multipleBatches: true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSendBlockBatches(t *testing.T) {
|
||||||
|
blockBatchSenderPrivKey, _ := crypto.GenerateKey()
|
||||||
|
txSignerPrivKey, _ := crypto.GenerateKey()
|
||||||
|
|
||||||
|
for testNum, testCase := range getTestCases(blockBatchSenderPrivKey) {
|
||||||
|
backendTimestamp = 0
|
||||||
|
api := getTestPublicTransactionPoolAPI(txSignerPrivKey, blockBatchSenderPrivKey, testCase.backendContext)
|
||||||
|
res := api.SendBlockBatches(testCase.inputCtx, testCase.inputMessageAndSig)
|
||||||
|
h := func(r []error) bool {
|
||||||
|
for _, e := range r {
|
||||||
|
if e != nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
hasErrors := h(res)
|
||||||
|
|
||||||
|
// For debugging and verification:
|
||||||
|
fmt.Printf("test case %d had output errors: %v\n", testNum, res)
|
||||||
|
if testCase.hasErrors && !hasErrors {
|
||||||
|
t.Fatalf("test case %d expected output errors but did not result in any. Errors: %v", testNum, res)
|
||||||
|
}
|
||||||
|
if !testCase.hasErrors && hasErrors {
|
||||||
|
t.Fatalf("test case %d did not expect output errors but resulted in %d. Errors: %v", testNum, len(res), res)
|
||||||
|
}
|
||||||
|
if hasErrors && len(testCase.backendContext.sendTxsErrors) > 0 {
|
||||||
|
// Note: Cannot handle test cases with multiple batches the same way because errors are aggregated from the endpoint and not from sendTxsErrors
|
||||||
|
if testCase.multipleBatches {
|
||||||
|
errorCount := func(r []error) int {
|
||||||
|
c := 0
|
||||||
|
for _, e := range r {
|
||||||
|
if e != nil {
|
||||||
|
c++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if errorCount(res) != errorCount(testCase.backendContext.sendTxsErrors) {
|
||||||
|
t.Fatalf("test case %d expected %d errors but resulted in %d", testNum, errorCount(res), errorCount(testCase.backendContext.sendTxsErrors))
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if len(res) != len(testCase.backendContext.sendTxsErrors) {
|
||||||
|
t.Fatalf("test case %d expected %d output errors but received %d. Errors: %v", testNum, len(testCase.backendContext.sendTxsErrors), len(res), res)
|
||||||
|
}
|
||||||
|
for i, err := range res {
|
||||||
|
if err != nil && testCase.backendContext.sendTxsErrors[i] == nil {
|
||||||
|
t.Fatalf("test case %d had an error output mismatch. Received error at index %d when one wasn't expected. Expected output: %v, output: %v", testNum, i, testCase.backendContext.sendTxsErrors, res)
|
||||||
|
}
|
||||||
|
if err == nil && testCase.backendContext.sendTxsErrors[i] != nil {
|
||||||
|
t.Fatalf("test case %d had an error output mismatch. Did not receive an error at index %d when one was expected. Expected output: %v, output: %v", testNum, i, testCase.backendContext.sendTxsErrors, res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if backendTimestamp != testCase.resultingTimestamp {
|
||||||
|
t.Fatalf("test case %d should have updated timestamp to %d but it was %d after execution.", testNum, testCase.resultingTimestamp, backendTimestamp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getDummyErrors(errorIndicies []int, outputSize int) []error {
|
||||||
|
errs := make([]error, outputSize)
|
||||||
|
for _, i := range errorIndicies {
|
||||||
|
errs[i] = fmt.Errorf("error %d", i)
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRandomRollupTransaction() *RollupTransaction {
|
||||||
|
gasLimit := hexutil.Uint64(uint64(0))
|
||||||
|
return &RollupTransaction{
|
||||||
|
Nonce: &internalTxNonce,
|
||||||
|
GasLimit: &gasLimit,
|
||||||
|
Sender: &internalTxSender,
|
||||||
|
Target: &internalTxTarget,
|
||||||
|
Calldata: &internalTxCalldata,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBlockBatchesInputMessageAndSignature(privKey *ecdsa.PrivateKey, timestamp int64, blockNumber int, batchSizes []int) []hexutil.Bytes {
|
||||||
|
ts := hexutil.Uint64(uint64(timestamp))
|
||||||
|
blockNum := hexutil.Uint64(uint64(blockNumber))
|
||||||
|
|
||||||
|
batches := make([][]*RollupTransaction, len(batchSizes))
|
||||||
|
for i, s := range batchSizes {
|
||||||
|
batches[i] = make([]*RollupTransaction, s)
|
||||||
|
for index := 0; index < s; index++ {
|
||||||
|
batches[i][index] = getRandomRollupTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bb := &BlockBatches{
|
||||||
|
Timestamp: &ts,
|
||||||
|
BlockNumber: &blockNum,
|
||||||
|
Batches: batches,
|
||||||
|
}
|
||||||
|
|
||||||
|
message, _ := json.Marshal(bb)
|
||||||
|
return getInputMessageAndSignature(message, privKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInputMessageAndSignature(message []byte, privKey *ecdsa.PrivateKey) []hexutil.Bytes {
|
||||||
|
sig, _ := crypto.Sign(crypto.Keccak256(message), privKey)
|
||||||
|
return []hexutil.Bytes{message, sig}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getFakeContext() context.Context {
|
||||||
|
return &awstesting.FakeContext{
|
||||||
|
Error: fmt.Errorf("fake error%s", "!"),
|
||||||
|
DoneCh: make(chan struct{}, 1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTestPublicTransactionPoolAPI(txSignerPrivKey *ecdsa.PrivateKey, blockBatchSenderPrivKey *ecdsa.PrivateKey, backendContext backendContext) *PublicTransactionPoolAPI {
|
||||||
|
backend := newMockBackend(&blockBatchSenderPrivKey.PublicKey, backendContext)
|
||||||
|
return NewPublicTransactionPoolAPI(backend, nil, txSignerPrivKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
type backendContext struct {
|
||||||
|
currentBlockNumber int64
|
||||||
|
signerNonce uint64
|
||||||
|
sendTxsErrors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
type mockBackend struct {
|
||||||
|
blockBatchSender *ecdsa.PublicKey
|
||||||
|
testContext backendContext
|
||||||
|
timestamp int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMockBackend(blockBatchSender *ecdsa.PublicKey, backendContext backendContext) mockBackend {
|
||||||
|
return mockBackend{
|
||||||
|
blockBatchSender: blockBatchSender,
|
||||||
|
testContext: backendContext,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) Downloader() *downloader.Downloader {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) ProtocolVersion() int {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) ChainDb() ethdb.Database {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) AccountManager() *accounts.Manager {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) ExtRPCEnabled() bool {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) RPCGasCap() *big.Int {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SetHead(number uint64) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetTd(hash common.Hash) *big.Int {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetEVM(ctx context.Context, msg core.Message, state *state.StateDB, header *types.Header) (*vm.EVM, func() error, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetPoolTransactions() (types.Transactions, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
|
||||||
|
return m.testContext.signerNonce, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) Stats() (pending int, queued int) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) BloomStatus() (uint64, uint64) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) GetLogs(ctx context.Context, blockHash common.Hash) ([][]*types.Log, error) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
|
||||||
|
panic("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SendTxs(ctx context.Context, signedTxs []*types.Transaction) []error {
|
||||||
|
if len(m.testContext.sendTxsErrors) == 0 || len(m.testContext.sendTxsErrors) != len(signedTxs) {
|
||||||
|
return make([]error, len(signedTxs))
|
||||||
|
}
|
||||||
|
return m.testContext.sendTxsErrors
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) SetTimestamp(timestamp int64) {
|
||||||
|
backendTimestamp = timestamp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) ChainConfig() *params.ChainConfig {
|
||||||
|
return ¶ms.ChainConfig{
|
||||||
|
BlockBatchesSender: m.blockBatchSender,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mockBackend) CurrentBlock() *types.Block {
|
||||||
|
header := &types.Header{
|
||||||
|
ParentHash: common.Hash{},
|
||||||
|
UncleHash: common.Hash{},
|
||||||
|
Coinbase: common.Address{},
|
||||||
|
Root: common.Hash{},
|
||||||
|
TxHash: common.Hash{},
|
||||||
|
ReceiptHash: common.Hash{},
|
||||||
|
Bloom: types.Bloom{},
|
||||||
|
Difficulty: nil,
|
||||||
|
Number: big.NewInt(m.testContext.currentBlockNumber),
|
||||||
|
GasLimit: 0,
|
||||||
|
GasUsed: 0,
|
||||||
|
Time: 0,
|
||||||
|
Extra: nil,
|
||||||
|
MixDigest: common.Hash{},
|
||||||
|
Nonce: types.BlockNonce{},
|
||||||
|
}
|
||||||
|
|
||||||
|
return types.NewBlock(header, []*types.Transaction{}, []*types.Header{}, []*types.Receipt{})
|
||||||
|
}
|
@ -82,6 +82,10 @@ type Backend interface {
|
|||||||
SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription
|
SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription
|
||||||
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
|
SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription
|
||||||
|
|
||||||
|
// Optimism-specific API
|
||||||
|
SendTxs(ctx context.Context, signedTxs []*types.Transaction) []error
|
||||||
|
SetTimestamp(timestamp int64)
|
||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
CurrentBlock() *types.Block
|
CurrentBlock() *types.Block
|
||||||
}
|
}
|
||||||
@ -102,7 +106,8 @@ func GetAPIs(apiBackend Backend) []rpc.API {
|
|||||||
}, {
|
}, {
|
||||||
Namespace: "eth",
|
Namespace: "eth",
|
||||||
Version: "1.0",
|
Version: "1.0",
|
||||||
Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock),
|
// TODO: Instantiate Private Key from env var here when we know it
|
||||||
|
Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock, nil),
|
||||||
Public: true,
|
Public: true,
|
||||||
}, {
|
}, {
|
||||||
Namespace: "txpool",
|
Namespace: "txpool",
|
||||||
|
@ -177,6 +177,14 @@ func (b *LesApiBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
|
|||||||
return b.eth.txPool.Add(ctx, signedTx)
|
return b.eth.txPool.Add(ctx, signedTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) SendTxs(ctx context.Context, signedTxs []*types.Transaction) []error {
|
||||||
|
return b.eth.txPool.AddBatch(ctx, signedTxs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) SetTimestamp(timestamp int64) {
|
||||||
|
// Intentionally empty because this is not needed for LightChain
|
||||||
|
}
|
||||||
|
|
||||||
func (b *LesApiBackend) RemoveTx(txHash common.Hash) {
|
func (b *LesApiBackend) RemoveTx(txHash common.Hash) {
|
||||||
b.eth.txPool.RemoveTx(txHash)
|
b.eth.txPool.RemoveTx(txHash)
|
||||||
}
|
}
|
||||||
|
@ -127,12 +127,12 @@ func prepare(n int, backend *backends.SimulatedBackend) {
|
|||||||
backend.SendTransaction(ctx, tx2)
|
backend.SendTransaction(ctx, tx2)
|
||||||
|
|
||||||
// user1 deploys a test contract
|
// user1 deploys a test contract
|
||||||
tx3, _ := types.SignTx(types.NewContractCreation(userNonce1+1, big.NewInt(0), 200000, big.NewInt(0), testContractCode), signer, userKey1)
|
tx3, _ := types.SignTx(types.NewContractCreation(userNonce1+1, big.NewInt(0), 200000, big.NewInt(0), testContractCode, nil), signer, userKey1)
|
||||||
backend.SendTransaction(ctx, tx3)
|
backend.SendTransaction(ctx, tx3)
|
||||||
testContractAddr = crypto.CreateAddress(userAddr1, userNonce1+1)
|
testContractAddr = crypto.CreateAddress(userAddr1, userNonce1+1)
|
||||||
|
|
||||||
// user1 deploys a event contract
|
// user1 deploys a event contract
|
||||||
tx4, _ := types.SignTx(types.NewContractCreation(userNonce1+2, big.NewInt(0), 200000, big.NewInt(0), testEventEmitterCode), signer, userKey1)
|
tx4, _ := types.SignTx(types.NewContractCreation(userNonce1+2, big.NewInt(0), 200000, big.NewInt(0), testEventEmitterCode, nil), signer, userKey1)
|
||||||
backend.SendTransaction(ctx, tx4)
|
backend.SendTransaction(ctx, tx4)
|
||||||
case 2:
|
case 2:
|
||||||
// bankUser transfer some ether to signer
|
// bankUser transfer some ether to signer
|
||||||
|
@ -222,7 +222,7 @@ func testChainGen(i int, block *core.BlockGen) {
|
|||||||
nonce := block.TxNonce(acc1Addr)
|
nonce := block.TxNonce(acc1Addr)
|
||||||
tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil), signer, acc1Key)
|
tx2, _ := types.SignTx(types.NewTransaction(nonce, acc2Addr, big.NewInt(1000), params.TxGas, nil, nil, nil), signer, acc1Key)
|
||||||
nonce++
|
nonce++
|
||||||
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode), signer, acc1Key)
|
tx3, _ := types.SignTx(types.NewContractCreation(nonce, big.NewInt(0), 1000000, big.NewInt(0), testContractCode, nil), signer, acc1Key)
|
||||||
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
testContractAddr = crypto.CreateAddress(acc1Addr, nonce)
|
||||||
block.AddTx(tx1)
|
block.AddTx(tx1)
|
||||||
block.AddTx(tx2)
|
block.AddTx(tx2)
|
||||||
|
@ -446,21 +446,25 @@ func (pool *TxPool) Add(ctx context.Context, tx *types.Transaction) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddTransactions adds all valid transactions to the pool and passes them to
|
// AddBatch adds all valid transactions to the pool and passes them to
|
||||||
// the tx relay backend
|
// the tx relay backend
|
||||||
func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) {
|
func (pool *TxPool) AddBatch(ctx context.Context, txs []*types.Transaction) []error {
|
||||||
pool.mu.Lock()
|
pool.mu.Lock()
|
||||||
defer pool.mu.Unlock()
|
defer pool.mu.Unlock()
|
||||||
var sendTx types.Transactions
|
var sendTx types.Transactions
|
||||||
|
|
||||||
for _, tx := range txs {
|
errors := make([]error, len(txs))
|
||||||
|
for i, tx := range txs {
|
||||||
if err := pool.add(ctx, tx); err == nil {
|
if err := pool.add(ctx, tx); err == nil {
|
||||||
sendTx = append(sendTx, tx)
|
sendTx = append(sendTx, tx)
|
||||||
|
} else {
|
||||||
|
errors[i] = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(sendTx) > 0 {
|
if len(sendTx) > 0 {
|
||||||
pool.relay.Send(sendTx)
|
pool.relay.Send(sendTx)
|
||||||
}
|
}
|
||||||
|
return errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTransaction returns a transaction if it is contained in the pool
|
// GetTransaction returns a transaction if it is contained in the pool
|
||||||
|
@ -345,12 +345,12 @@ func (w *worker) newWorkLoop(recommit time.Duration) {
|
|||||||
select {
|
select {
|
||||||
case <-w.startCh:
|
case <-w.startCh:
|
||||||
clearPending(w.chain.CurrentBlock().NumberU64())
|
clearPending(w.chain.CurrentBlock().NumberU64())
|
||||||
timestamp = time.Now().Unix()
|
timestamp = w.chain.CurrentTimestamp()
|
||||||
commit(false, commitInterruptNewHead)
|
commit(false, commitInterruptNewHead)
|
||||||
|
|
||||||
case head := <-w.chainHeadCh:
|
case head := <-w.chainHeadCh:
|
||||||
clearPending(head.Block.NumberU64())
|
clearPending(head.Block.NumberU64())
|
||||||
timestamp = time.Now().Unix()
|
timestamp = w.chain.CurrentTimestamp()
|
||||||
commit(false, commitInterruptNewHead)
|
commit(false, commitInterruptNewHead)
|
||||||
|
|
||||||
case <-timer.C:
|
case <-timer.C:
|
||||||
@ -482,7 +482,7 @@ func (w *worker) mainLoop() {
|
|||||||
// If clique is running in dev mode(period is 0), disable
|
// If clique is running in dev mode(period is 0), disable
|
||||||
// advance sealing here.
|
// advance sealing here.
|
||||||
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 {
|
if w.chainConfig.Clique != nil && w.chainConfig.Clique.Period == 0 {
|
||||||
w.commitNewWork(nil, true, time.Now().Unix())
|
w.commitNewWork(nil, true, w.chain.CurrentTimestamp())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
atomic.AddInt32(&w.newTxs, int32(len(ev.Txs)))
|
atomic.AddInt32(&w.newTxs, int32(len(ev.Txs)))
|
||||||
@ -834,15 +834,16 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
|
|||||||
tstart := time.Now()
|
tstart := time.Now()
|
||||||
parent := w.chain.CurrentBlock()
|
parent := w.chain.CurrentBlock()
|
||||||
|
|
||||||
if parent.Time() >= uint64(timestamp) {
|
// TODO: Is there some other sensible check that we can do in place of the below code with timestamps set from L1?
|
||||||
timestamp = int64(parent.Time() + 1)
|
//if parent.Time() >= uint64(timestamp) {
|
||||||
}
|
// timestamp = int64(parent.Time() + 1)
|
||||||
|
//}
|
||||||
// this will ensure we're not going off too far in the future
|
// this will ensure we're not going off too far in the future
|
||||||
if now := time.Now().Unix(); timestamp > now+1 {
|
//if now := time.Now().Unix(); timestamp > now+1 {
|
||||||
wait := time.Duration(timestamp-now) * time.Second
|
// wait := time.Duration(timestamp-now) * time.Second
|
||||||
log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait))
|
// log.Info("Mining too far in the future", "wait", common.PrettyDuration(wait))
|
||||||
time.Sleep(wait)
|
// time.Sleep(wait)
|
||||||
}
|
//}
|
||||||
|
|
||||||
num := parent.Number()
|
num := parent.Number()
|
||||||
header := &types.Header{
|
header := &types.Header{
|
||||||
|
@ -169,7 +169,7 @@ func (b *testWorkerBackend) newRandomUncle() *types.Block {
|
|||||||
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
func (b *testWorkerBackend) newRandomTx(creation bool) *types.Transaction {
|
||||||
var tx *types.Transaction
|
var tx *types.Transaction
|
||||||
if creation {
|
if creation {
|
||||||
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode)), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewContractCreation(b.txPool.Nonce(testBankAddress), big.NewInt(0), testGas, nil, common.FromHex(testCode), nil), types.HomesteadSigner{}, testBankKey)
|
||||||
} else {
|
} else {
|
||||||
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil), types.HomesteadSigner{}, testBankKey)
|
tx, _ = types.SignTx(types.NewTransaction(b.txPool.Nonce(testBankAddress), testUserAddress, big.NewInt(1000), params.TxGas, nil, nil, nil), types.HomesteadSigner{}, testBankKey)
|
||||||
}
|
}
|
||||||
|
@ -197,17 +197,11 @@ type Transaction struct {
|
|||||||
tx *types.Transaction
|
tx *types.Transaction
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewContractCreation creates a new transaction for deploying a new contract with
|
|
||||||
// the given properties.
|
|
||||||
func NewContractCreation(nonce int64, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction {
|
|
||||||
return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewTransaction creates a new transaction with the given properties. Contracts
|
// NewTransaction creates a new transaction with the given properties. Contracts
|
||||||
// can be created by transacting with a nil recipient.
|
// can be created by transacting with a nil recipient.
|
||||||
func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction {
|
func NewTransaction(nonce int64, to *Address, amount *BigInt, gasLimit int64, gasPrice *BigInt, data []byte) *Transaction {
|
||||||
if to == nil {
|
if to == nil {
|
||||||
return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data))}
|
return &Transaction{types.NewContractCreation(uint64(nonce), amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil)}
|
||||||
}
|
}
|
||||||
return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil)}
|
return &Transaction{types.NewTransaction(uint64(nonce), to.address, amount.bigint, uint64(gasLimit), gasPrice.bigint, common.CopyBytes(data), nil)}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package params
|
package params
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/ecdsa"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
@ -217,21 +218,23 @@ var (
|
|||||||
Threshold: 2,
|
Threshold: 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Fill out BlockBatchesSender Address when we know it
|
||||||
|
|
||||||
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
// AllEthashProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Ethash consensus.
|
// and accepted by the Ethereum core developers into the Ethash consensus.
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllEthashProtocolChanges = &ChainConfig{big.NewInt(108), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
|
AllEthashProtocolChanges = &ChainConfig{big.NewInt(108), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, nil}
|
||||||
|
|
||||||
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
|
||||||
// and accepted by the Ethereum core developers into the Clique consensus.
|
// and accepted by the Ethereum core developers into the Clique consensus.
|
||||||
//
|
//
|
||||||
// This configuration is intentionally not using keyed fields to force anyone
|
// This configuration is intentionally not using keyed fields to force anyone
|
||||||
// adding flags to the config to also have to set these fields.
|
// adding flags to the config to also have to set these fields.
|
||||||
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(108), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
|
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(108), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}, nil}
|
||||||
|
|
||||||
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil}
|
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, new(EthashConfig), nil, nil}
|
||||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -307,6 +310,8 @@ type ChainConfig struct {
|
|||||||
// Various consensus engines
|
// Various consensus engines
|
||||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||||
Clique *CliqueConfig `json:"clique,omitempty"`
|
Clique *CliqueConfig `json:"clique,omitempty"`
|
||||||
|
|
||||||
|
BlockBatchesSender *ecdsa.PublicKey `json:"blockBatchSender,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
// EthashConfig is the consensus engine configs for proof-of-work based sealing.
|
||||||
|
@ -95,7 +95,7 @@ func (args *SendTxArgs) toTransaction() *types.Transaction {
|
|||||||
input = *args.Input
|
input = *args.Input
|
||||||
}
|
}
|
||||||
if args.To == nil {
|
if args.To == nil {
|
||||||
return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), uint64(args.Gas), (*big.Int)(&args.GasPrice), input)
|
return types.NewContractCreation(uint64(args.Nonce), (*big.Int)(&args.Value), uint64(args.Gas), (*big.Int)(&args.GasPrice), input, nil)
|
||||||
}
|
}
|
||||||
var l1MessageSender *common.Address = nil
|
var l1MessageSender *common.Address = nil
|
||||||
if args.L1MessageSender != nil {
|
if args.L1MessageSender != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user