func RunState(ruleSet RuleSet, statedb *state.StateDB, env, tx map[string]string) ([]byte, vm.Logs, *big.Int, error) { var ( data = common.FromHex(tx["data"]) gas = common.Big(tx["gasLimit"]) price = common.Big(tx["gasPrice"]) value = common.Big(tx["value"]) nonce = common.Big(tx["nonce"]).Uint64() ) var to *common.Address if len(tx["to"]) > 2 { t := common.HexToAddress(tx["to"]) to = &t } // Set pre compiled contracts vm.Precompiled = vm.PrecompiledContracts() snapshot := statedb.Copy() gaspool := new(core.GasPool).AddGas(common.Big(env["currentGasLimit"])) key, _ := hex.DecodeString(tx["secretKey"]) addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) message := NewMessage(addr, to, data, value, gas, price, nonce) vmenv := NewEnvFromMap(ruleSet, statedb, env, tx) vmenv.origin = addr ret, _, err := core.ApplyMessage(vmenv, message, gaspool) if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || core.IsGasLimitErr(err) { statedb.Set(snapshot) } statedb.Commit() return ret, vmenv.state.Logs(), vmenv.Gas, err }
// InsertChain will attempt to insert the given chain in to the canonical chain or, otherwise, create a fork. It an error is returned // it will return the index number of the failing block as well an error describing what went wrong (for possible errors see core/errors.go). func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) { self.wg.Add(1) defer self.wg.Done() self.chainmu.Lock() defer self.chainmu.Unlock() // A queued approach to delivering events. This is generally // faster than direct delivery and requires much less mutex // acquiring. var ( stats struct{ queued, processed, ignored int } events = make([]interface{}, 0, len(chain)) coalescedLogs vm.Logs tstart = time.Now() nonceChecked = make([]bool, len(chain)) statedb *state.StateDB ) // Start the parallel nonce verifier. nonceAbort, nonceResults := verifyNoncesFromBlocks(self.pow, chain) defer close(nonceAbort) txcount := 0 for i, block := range chain { if atomic.LoadInt32(&self.procInterrupt) == 1 { glog.V(logger.Debug).Infoln("Premature abort during block chain processing") break } bstart := time.Now() // Wait for block i's nonce to be verified before processing // its state transition. for !nonceChecked[i] { r := <-nonceResults nonceChecked[r.index] = true if !r.valid { block := chain[r.index] return r.index, &BlockNonceErr{Hash: block.Hash(), Number: block.Number(), Nonce: block.Nonce()} } } if BadHashes[block.Hash()] { err := BadHashError(block.Hash()) reportBlock(block, err) return i, err } // Stage 1 validation of the block using the chain's validator // interface. err := self.Validator().ValidateBlock(block) if err != nil { if IsKnownBlockErr(err) { stats.ignored++ continue } if err == BlockFutureErr { // Allow up to MaxFuture second in the future blocks. If this limit // is exceeded the chain is discarded and processed at a later time // if given. max := big.NewInt(time.Now().Unix() + maxTimeFutureBlocks) if block.Time().Cmp(max) == 1 { return i, fmt.Errorf("%v: BlockFutureErr, %v > %v", BlockFutureErr, block.Time(), max) } self.futureBlocks.Add(block.Hash(), block) stats.queued++ continue } if IsParentErr(err) && self.futureBlocks.Contains(block.ParentHash()) { self.futureBlocks.Add(block.Hash(), block) stats.queued++ continue } reportBlock(block, err) return i, err } // Create a new statedb using the parent block and report an // error if it fails. if statedb == nil { statedb, err = state.New(self.GetBlock(block.ParentHash()).Root(), self.chainDb) } else { err = statedb.Reset(chain[i-1].Root()) } if err != nil { reportBlock(block, err) return i, err } // Process block using the parent state as reference point. receipts, logs, usedGas, err := self.processor.Process(block, statedb, self.config.VmConfig) if err != nil { reportBlock(block, err) return i, err } // Validate the state using the default validator err = self.Validator().ValidateState(block, self.GetBlock(block.ParentHash()), statedb, receipts, usedGas) if err != nil { reportBlock(block, err) return i, err } // Write state changes to database _, err = statedb.Commit() if err != nil { return i, err } // coalesce logs for later processing coalescedLogs = append(coalescedLogs, logs...) if err := WriteBlockReceipts(self.chainDb, block.Hash(), receipts); err != nil { return i, err } txcount += len(block.Transactions()) // write the block to the chain and get the status status, err := self.WriteBlock(block) if err != nil { return i, err } switch status { case CanonStatTy: if glog.V(logger.Debug) { glog.Infof("[%v] inserted block #%d (%d TXs %v G %d UNCs) (%x...). Took %v\n", time.Now().UnixNano(), block.Number(), len(block.Transactions()), block.GasUsed(), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart)) } events = append(events, ChainEvent{block, block.Hash(), logs}) // This puts transactions in a extra db for rpc if err := WriteTransactions(self.chainDb, block); err != nil { return i, err } // store the receipts if err := WriteReceipts(self.chainDb, receipts); err != nil { return i, err } // Write map map bloom filters if err := WriteMipmapBloom(self.chainDb, block.NumberU64(), receipts); err != nil { return i, err } case SideStatTy: if glog.V(logger.Detail) { glog.Infof("inserted forked block #%d (TD=%v) (%d TXs %d UNCs) (%x...). Took %v\n", block.Number(), block.Difficulty(), len(block.Transactions()), len(block.Uncles()), block.Hash().Bytes()[0:4], time.Since(bstart)) } events = append(events, ChainSideEvent{block, logs}) case SplitStatTy: events = append(events, ChainSplitEvent{block, logs}) } stats.processed++ } if (stats.queued > 0 || stats.processed > 0 || stats.ignored > 0) && bool(glog.V(logger.Info)) { tend := time.Since(tstart) start, end := chain[0], chain[len(chain)-1] glog.Infof("imported %d block(s) (%d queued %d ignored) including %d txs in %v. #%v [%x / %x]\n", stats.processed, stats.queued, stats.ignored, txcount, tend, end.Number(), start.Hash().Bytes()[:4], end.Hash().Bytes()[:4]) } go self.postChainEvents(events, coalescedLogs) return 0, nil }