// validatePool removes invalid and processed transactions from the main pool. // If a transaction is removed for being invalid (e.g. out of funds), all sub- // sequent (Still valid) transactions are moved back into the future queue. This // is important to prevent a drained account from DOSing the network with non // executable transactions. func (pool *TxPool) validatePool() { state, err := pool.currentState() if err != nil { glog.V(logger.Info).Infoln("failed to get current state: %v", err) return } balanceCache := make(map[common.Address]*big.Int) // Clean up the pending pool, accumulating invalid nonces gaps := make(map[common.Address]uint64) for hash, tx := range pool.pending { sender, _ := tx.From() // err already checked // Perform light nonce and balance validation balance := balanceCache[sender] if balance == nil { balance = state.GetBalance(sender) balanceCache[sender] = balance } if past := state.GetNonce(sender) > tx.Nonce(); past || balance.Cmp(tx.Cost()) < 0 { // Remove an already past it invalidated transaction if glog.V(logger.Core) { glog.Infof("removed tx (%v) from pool: low tx nonce or out of funds\n", tx) } delete(pool.pending, hash) // Track the smallest invalid nonce to postpone subsequent transactions if !past { if prev, ok := gaps[sender]; !ok || tx.Nonce() < prev { gaps[sender] = tx.Nonce() } } } } // Move all transactions after a gap back to the future queue if len(gaps) > 0 { for hash, tx := range pool.pending { sender, _ := tx.From() if gap, ok := gaps[sender]; ok && tx.Nonce() >= gap { if glog.V(logger.Core) { glog.Infof("postponed tx (%v) due to introduced gap\n", tx) } pool.queueTx(hash, tx) delete(pool.pending, hash) } } } }
func testGetNodeData(t *testing.T, protocol int) { // Define three accounts to simulate transactions with acc1Key, _ := crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") acc2Key, _ := crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") acc1Addr := crypto.PubkeyToAddress(acc1Key.PublicKey) acc2Addr := crypto.PubkeyToAddress(acc2Key.PublicKey) // Create a chain generator with some simple transactions (blatantly stolen from @fjl/chain_makerts_test) generator := func(i int, block *core.BlockGen) { switch i { case 0: // In block 1, the test bank sends account #1 some ether. tx, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(10000), params.TxGas, nil, nil).SignECDSA(testBankKey) block.AddTx(tx) case 1: // In block 2, the test bank sends some more ether to account #1. // acc1Addr passes it on to account #2. tx1, _ := types.NewTransaction(block.TxNonce(testBankAddress), acc1Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(testBankKey) tx2, _ := types.NewTransaction(block.TxNonce(acc1Addr), acc2Addr, big.NewInt(1000), params.TxGas, nil, nil).SignECDSA(acc1Key) block.AddTx(tx1) block.AddTx(tx2) case 2: // Block 3 is empty but was mined by account #2. block.SetCoinbase(acc2Addr) block.SetExtra([]byte("yeehaw")) case 3: // Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data). b2 := block.PrevBlock(1).Header() b2.Extra = []byte("foo") block.AddUncle(b2) b3 := block.PrevBlock(2).Header() b3.Extra = []byte("foo") block.AddUncle(b3) } } // Assemble the test environment pm := newTestProtocolManagerMust(t, false, 4, generator, nil) peer, _ := newTestPeer("peer", protocol, pm, true) defer peer.close() // Fetch for now the entire chain db hashes := []common.Hash{} for _, key := range pm.chaindb.(*ethdb.MemDatabase).Keys() { if len(key) == len(common.Hash{}) { hashes = append(hashes, common.BytesToHash(key)) } } p2p.Send(peer.app, 0x0d, hashes) msg, err := peer.app.ReadMsg() if err != nil { t.Fatalf("failed to read node data response: %v", err) } if msg.Code != 0x0e { t.Fatalf("response packet code mismatch: have %x, want %x", msg.Code, 0x0c) } var data [][]byte if err := msg.Decode(&data); err != nil { t.Fatalf("failed to decode response node data: %v", err) } // Verify that all hashes correspond to the requested data, and reconstruct a state tree for i, want := range hashes { if hash := crypto.Sha3Hash(data[i]); hash != want { fmt.Errorf("data hash mismatch: have %x, want %x", hash, want) } } statedb, _ := ethdb.NewMemDatabase() for i := 0; i < len(data); i++ { statedb.Put(hashes[i].Bytes(), data[i]) } accounts := []common.Address{testBankAddress, acc1Addr, acc2Addr} for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { trie, _ := state.New(pm.blockchain.GetBlockByNumber(i).Root(), statedb) for j, acc := range accounts { state, _ := pm.blockchain.State() bw := state.GetBalance(acc) bh := trie.GetBalance(acc) if (bw != nil && bh == nil) || (bw == nil && bh != nil) { t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) } if bw != nil && bh != nil && bw.Cmp(bw) != 0 { t.Errorf("test %d, account %d: balance mismatch: have %v, want %v", i, j, bh, bw) } } } }
func (self *JitVm) Run(me, caller ContextRef, code []byte, value, gas, price *big.Int, callData []byte) (ret []byte, err error) { // TODO: depth is increased but never checked by VM. VM should not know about it at all. self.env.SetDepth(self.env.Depth() + 1) // TODO: Move it to Env.Call() or sth if Precompiled[string(me.Address())] != nil { // if it's address of precopiled contract // fallback to standard VM stdVm := New(self.env) return stdVm.Run(me, caller, code, value, gas, price, callData) } if self.me != nil { panic("JitVm.Run() can be called only once per JitVm instance") } self.me = me self.callerAddr = caller.Address() self.price = price self.data.gas = gas.Int64() self.data.gasPrice = price.Int64() self.data.callData = getDataPtr(callData) self.data.callDataSize = uint64(len(callData)) self.data.address = address2llvm(self.me.Address()) self.data.caller = address2llvm(caller.Address()) self.data.origin = address2llvm(self.env.Origin()) self.data.callValue = big2llvm(value) self.data.coinBase = address2llvm(self.env.Coinbase()) self.data.difficulty = big2llvm(self.env.Difficulty()) self.data.gasLimit = big2llvm(self.env.GasLimit()) self.data.number = self.env.BlockNumber().Uint64() self.data.timestamp = self.env.Time() self.data.code = getDataPtr(code) self.data.codeSize = uint64(len(code)) self.data.codeHash = hash2llvm(crypto.Sha3(code)) // TODO: Get already computed hash? jit := C.evmjit_create() retCode := C.evmjit_run(jit, unsafe.Pointer(&self.data), unsafe.Pointer(self)) if retCode < 0 { err = errors.New("OOG from JIT") gas.SetInt64(0) // Set gas to 0, JIT does not bother } else { gas.SetInt64(self.data.gas) if retCode == 1 { // RETURN ret = C.GoBytes(unsafe.Pointer(self.data.callData), C.int(self.data.callDataSize)) } else if retCode == 2 { // SUICIDE // TODO: Suicide support logic should be moved to Env to be shared by VM implementations state := self.Env().State() receiverAddr := llvm2hashRef(bswap(&self.data.address)) receiver := state.GetOrNewStateObject(receiverAddr) balance := state.GetBalance(me.Address()) receiver.AddBalance(balance) state.Delete(me.Address()) } } C.evmjit_destroy(jit) return }