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" | ||||||
| @ -1179,13 +1181,19 @@ func newRPCTransactionFromBlockHash(b *types.Block, hash common.Hash) *RPCTransa | |||||||
| 
 | 
 | ||||||
| // PublicTransactionPoolAPI exposes methods for the RPC interface
 | // PublicTransactionPoolAPI exposes methods for the RPC interface
 | ||||||
| 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,8 +106,9 @@ 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
 | ||||||
| 			Public:    true, | 			Service: NewPublicTransactionPoolAPI(apiBackend, nonceLock, nil), | ||||||
|  | 			Public:  true, | ||||||
| 		}, { | 		}, { | ||||||
| 			Namespace: "txpool", | 			Namespace: "txpool", | ||||||
| 			Version:   "1.0", | 			Version:   "1.0", | ||||||
|  | |||||||
| @ -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