Best K6 code snippet using types.insert
blockchain_test.go
Source:blockchain_test.go
...76 )77 if full {78 blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, db, forkSeed)79 if _, err := blockchain2.InsertChain(blockChainB); err != nil {80 t.Fatalf("failed to insert forking chain: %v", err)81 }82 } else {83 headerChainB = makeHeaderChain(blockchain2.CurrentHeader(), n, db, forkSeed)84 if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil {85 t.Fatalf("failed to insert forking chain: %v", err)86 }87 }88 // Sanity check that the forked chain can be imported into the original89 var tdPre, tdPost *big.Int90 if full {91 tdPre = blockchain.GetTdByHash(blockchain.CurrentBlock().Hash())92 if err := testBlockChainImport(blockChainB, blockchain); err != nil {93 t.Fatalf("failed to import forked block chain: %v", err)94 }95 tdPost = blockchain.GetTdByHash(blockChainB[len(blockChainB)-1].Hash())96 } else {97 tdPre = blockchain.GetTdByHash(blockchain.CurrentHeader().Hash())98 if err := testHeaderChainImport(headerChainB, blockchain); err != nil {99 t.Fatalf("failed to import forked header chain: %v", err)100 }101 tdPost = blockchain.GetTdByHash(headerChainB[len(headerChainB)-1].Hash())102 }103 // Compare the total difficulties of the chains104 comparator(tdPre, tdPost)105}106func printChain(bc *BlockChain) {107 for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- {108 b := bc.GetBlockByNumber(uint64(i))109 fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty())110 }111}112// testBlockChainImport tries to process a chain of blocks, writing them into113// the database if successful.114func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error {115 for _, block := range chain {116 // Try and process the block117 err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true)118 if err == nil {119 err = blockchain.validator.ValidateBody(block)120 }121 if err != nil {122 if err == ErrKnownBlock {123 continue124 }125 return err126 }127 statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.stateCache)128 if err != nil {129 return err130 }131 receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vm.Config{})132 if err != nil {133 blockchain.reportBlock(block, receipts, err)134 return err135 }136 err = blockchain.validator.ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas)137 if err != nil {138 blockchain.reportBlock(block, receipts, err)139 return err140 }141 blockchain.mu.Lock()142 WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash())))143 WriteBlock(blockchain.chainDb, block)144 statedb.CommitTo(blockchain.chainDb, false)145 blockchain.mu.Unlock()146 }147 return nil148}149// testHeaderChainImport tries to process a chain of header, writing them into150// the database if successful.151func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error {152 for _, header := range chain {153 // Try and validate the header154 if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil {155 return err156 }157 // Manually insert the header into the database, but don't reorganise (allows subsequent testing)158 blockchain.mu.Lock()159 WriteTd(blockchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash)))160 WriteHeader(blockchain.chainDb, header)161 blockchain.mu.Unlock()162 }163 return nil164}165func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) {166 _, err := blockchain.InsertChain(chain)167 if err != nil {168 fmt.Println(err)169 t.FailNow()170 }171 done <- true172}173func TestLastBlock(t *testing.T) {174 bchain := newTestBlockChain(false)175 defer bchain.Stop()176 block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0]177 bchain.insert(block)178 if block.Hash() != GetHeadBlockHash(bchain.chainDb) {179 t.Errorf("Write/Get HeadBlockHash failed")180 }181}182// Tests that given a starting canonical chain of a given size, it can be extended183// with various length chains.184func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) }185func TestExtendCanonicalBlocks(t *testing.T) { testExtendCanonical(t, true) }186func testExtendCanonical(t *testing.T, full bool) {187 length := 5188 // Make first chain starting from genesis189 _, processor, err := newCanonical(length, full)190 if err != nil {191 t.Fatalf("failed to make new canonical chain: %v", err)192 }193 defer processor.Stop()194 // Define the difficulty comparator195 better := func(td1, td2 *big.Int) {196 if td2.Cmp(td1) <= 0 {197 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)198 }199 }200 // Start fork from current height201 testFork(t, processor, length, 1, full, better)202 testFork(t, processor, length, 2, full, better)203 testFork(t, processor, length, 5, full, better)204 testFork(t, processor, length, 10, full, better)205}206// Tests that given a starting canonical chain of a given size, creating shorter207// forks do not take canonical ownership.208func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) }209func TestShorterForkBlocks(t *testing.T) { testShorterFork(t, true) }210func testShorterFork(t *testing.T, full bool) {211 length := 10212 // Make first chain starting from genesis213 _, processor, err := newCanonical(length, full)214 if err != nil {215 t.Fatalf("failed to make new canonical chain: %v", err)216 }217 defer processor.Stop()218 // Define the difficulty comparator219 worse := func(td1, td2 *big.Int) {220 if td2.Cmp(td1) >= 0 {221 t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1)222 }223 }224 // Sum of numbers must be less than `length` for this to be a shorter fork225 testFork(t, processor, 0, 3, full, worse)226 testFork(t, processor, 0, 7, full, worse)227 testFork(t, processor, 1, 1, full, worse)228 testFork(t, processor, 1, 7, full, worse)229 testFork(t, processor, 5, 3, full, worse)230 testFork(t, processor, 5, 4, full, worse)231}232// Tests that given a starting canonical chain of a given size, creating longer233// forks do take canonical ownership.234func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) }235func TestLongerForkBlocks(t *testing.T) { testLongerFork(t, true) }236func testLongerFork(t *testing.T, full bool) {237 length := 10238 // Make first chain starting from genesis239 _, processor, err := newCanonical(length, full)240 if err != nil {241 t.Fatalf("failed to make new canonical chain: %v", err)242 }243 defer processor.Stop()244 // Define the difficulty comparator245 better := func(td1, td2 *big.Int) {246 if td2.Cmp(td1) <= 0 {247 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1)248 }249 }250 // Sum of numbers must be greater than `length` for this to be a longer fork251 testFork(t, processor, 0, 11, full, better)252 testFork(t, processor, 0, 15, full, better)253 testFork(t, processor, 1, 10, full, better)254 testFork(t, processor, 1, 12, full, better)255 testFork(t, processor, 5, 6, full, better)256 testFork(t, processor, 5, 8, full, better)257}258// Tests that given a starting canonical chain of a given size, creating equal259// forks do take canonical ownership.260func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) }261func TestEqualForkBlocks(t *testing.T) { testEqualFork(t, true) }262func testEqualFork(t *testing.T, full bool) {263 length := 10264 // Make first chain starting from genesis265 _, processor, err := newCanonical(length, full)266 if err != nil {267 t.Fatalf("failed to make new canonical chain: %v", err)268 }269 defer processor.Stop()270 // Define the difficulty comparator271 equal := func(td1, td2 *big.Int) {272 if td2.Cmp(td1) != 0 {273 t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1)274 }275 }276 // Sum of numbers must be equal to `length` for this to be an equal fork277 testFork(t, processor, 0, 10, full, equal)278 testFork(t, processor, 1, 9, full, equal)279 testFork(t, processor, 2, 8, full, equal)280 testFork(t, processor, 5, 5, full, equal)281 testFork(t, processor, 6, 4, full, equal)282 testFork(t, processor, 9, 1, full, equal)283}284// Tests that chains missing links do not get accepted by the processor.285func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) }286func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) }287func testBrokenChain(t *testing.T, full bool) {288 // Make chain starting from genesis289 db, blockchain, err := newCanonical(10, full)290 if err != nil {291 t.Fatalf("failed to make new canonical chain: %v", err)292 }293 defer blockchain.Stop()294 // Create a forked chain, and try to insert with a missing link295 if full {296 chain := makeBlockChain(blockchain.CurrentBlock(), 5, db, forkSeed)[1:]297 if err := testBlockChainImport(chain, blockchain); err == nil {298 t.Errorf("broken block chain not reported")299 }300 } else {301 chain := makeHeaderChain(blockchain.CurrentHeader(), 5, db, forkSeed)[1:]302 if err := testHeaderChainImport(chain, blockchain); err == nil {303 t.Errorf("broken header chain not reported")304 }305 }306}307type bproc struct{}308func (bproc) ValidateBody(*types.Block) error { return nil }309func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error {310 return nil311}312func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) {313 return nil, nil, new(big.Int), nil314}315func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header {316 blocks := makeBlockChainWithDiff(genesis, d, seed)317 headers := make([]*types.Header, len(blocks))318 for i, block := range blocks {319 headers[i] = block.Header()320 }321 return headers322}323func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block {324 var chain []*types.Block325 for i, difficulty := range d {326 header := &types.Header{327 Coinbase: common.Address{seed},328 Number: big.NewInt(int64(i + 1)),329 Difficulty: big.NewInt(int64(difficulty)),330 UncleHash: types.EmptyUncleHash,331 TxHash: types.EmptyRootHash,332 ReceiptHash: types.EmptyRootHash,333 Time: big.NewInt(int64(i) + 1),334 }335 if i == 0 {336 header.ParentHash = genesis.Hash()337 } else {338 header.ParentHash = chain[i-1].Hash()339 }340 block := types.NewBlockWithHeader(header)341 chain = append(chain, block)342 }343 return chain344}345// Tests that reorganising a long difficult chain after a short easy one346// overwrites the canonical numbers and links in the database.347func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) }348func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) }349func testReorgLong(t *testing.T, full bool) {350 testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10, full)351}352// Tests that reorganising a short difficult chain after a long easy one353// overwrites the canonical numbers and links in the database.354func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) }355func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) }356func testReorgShort(t *testing.T, full bool) {357 testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11, full)358}359func testReorg(t *testing.T, first, second []int, td int64, full bool) {360 bc := newTestBlockChain(true)361 defer bc.Stop()362 // Insert an easy and a difficult chain afterwards363 if full {364 bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11))365 bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22))366 } else {367 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1)368 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1)369 }370 // Check that the chain is valid number and link wise371 if full {372 prev := bc.CurrentBlock()373 for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) {374 if prev.ParentHash() != block.Hash() {375 t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash())376 }377 }378 } else {379 prev := bc.CurrentHeader()380 for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) {381 if prev.ParentHash != header.Hash() {382 t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash())383 }384 }385 }386 // Make sure the chain total difficulty is the correct one387 want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td))388 if full {389 if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 {390 t.Errorf("total difficulty mismatch: have %v, want %v", have, want)391 }392 } else {393 if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 {394 t.Errorf("total difficulty mismatch: have %v, want %v", have, want)395 }396 }397}398// Tests that the insertion functions detect banned hashes.399func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) }400func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) }401func testBadHashes(t *testing.T, full bool) {402 bc := newTestBlockChain(true)403 defer bc.Stop()404 // Create a chain, ban a hash and try to import405 var err error406 if full {407 blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)408 BadHashes[blocks[2].Header().Hash()] = true409 _, err = bc.InsertChain(blocks)410 } else {411 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10)412 BadHashes[headers[2].Hash()] = true413 _, err = bc.InsertHeaderChain(headers, 1)414 }415 if err != ErrBlacklistedHash {416 t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash)417 }418}419// Tests that bad hashes are detected on boot, and the chain rolled back to a420// good state prior to the bad hash.421func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) }422func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) }423func testReorgBadHashes(t *testing.T, full bool) {424 bc := newTestBlockChain(true)425 defer bc.Stop()426 // Create a chain, import and ban afterwards427 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)428 blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10)429 if full {430 if _, err := bc.InsertChain(blocks); err != nil {431 t.Fatalf("failed to import blocks: %v", err)432 }433 if bc.CurrentBlock().Hash() != blocks[3].Hash() {434 t.Errorf("last block hash mismatch: have: %x, want %x", bc.CurrentBlock().Hash(), blocks[3].Header().Hash())435 }436 BadHashes[blocks[3].Header().Hash()] = true437 defer func() { delete(BadHashes, blocks[3].Header().Hash()) }()438 } else {439 if _, err := bc.InsertHeaderChain(headers, 1); err != nil {440 t.Fatalf("failed to import headers: %v", err)441 }442 if bc.CurrentHeader().Hash() != headers[3].Hash() {443 t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash())444 }445 BadHashes[headers[3].Hash()] = true446 defer func() { delete(BadHashes, headers[3].Hash()) }()447 }448 // Create a new BlockChain and check that it rolled back the state.449 ncm, err := NewBlockChain(bc.chainDb, bc.config, ethash.NewFaker(), vm.Config{})450 if err != nil {451 t.Fatalf("failed to create new chain manager: %v", err)452 }453 defer ncm.Stop()454 if full {455 if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() {456 t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash())457 }458 if blocks[2].Header().GasLimit.Cmp(ncm.GasLimit()) != 0 {459 t.Errorf("last block gasLimit mismatch: have: %x, want %x", ncm.GasLimit(), blocks[2].Header().GasLimit)460 }461 } else {462 if ncm.CurrentHeader().Hash() != headers[2].Hash() {463 t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash())464 }465 }466}467// Tests chain insertions in the face of one entity containing an invalid nonce.468func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) }469func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) }470func testInsertNonceError(t *testing.T, full bool) {471 for i := 1; i < 25 && !t.Failed(); i++ {472 // Create a pristine chain and database473 db, blockchain, err := newCanonical(0, full)474 if err != nil {475 t.Fatalf("failed to create pristine chain: %v", err)476 }477 defer blockchain.Stop()478 // Create and insert a chain with a failing nonce479 var (480 failAt int481 failRes int482 failNum uint64483 )484 if full {485 blocks := makeBlockChain(blockchain.CurrentBlock(), i, db, 0)486 failAt = rand.Int() % len(blocks)487 failNum = blocks[failAt].NumberU64()488 blockchain.engine = ethash.NewFakeFailer(failNum)489 failRes, err = blockchain.InsertChain(blocks)490 } else {491 headers := makeHeaderChain(blockchain.CurrentHeader(), i, db, 0)492 failAt = rand.Int() % len(headers)493 failNum = headers[failAt].Number.Uint64()494 blockchain.engine = ethash.NewFakeFailer(failNum)495 blockchain.hc.engine = blockchain.engine496 failRes, err = blockchain.InsertHeaderChain(headers, 1)497 }498 // Check that the returned error indicates the failure.499 if failRes != failAt {500 t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt)501 }502 // Check that all no blocks after the failing block have been inserted.503 for j := 0; j < i-failAt; j++ {504 if full {505 if block := blockchain.GetBlockByNumber(failNum + uint64(j)); block != nil {506 t.Errorf("test %d: invalid block in chain: %v", i, block)507 }508 } else {509 if header := blockchain.GetHeaderByNumber(failNum + uint64(j)); header != nil {510 t.Errorf("test %d: invalid header in chain: %v", i, header)511 }512 }513 }514 }515}516// Tests that fast importing a block chain produces the same chain data as the517// classical full block processing.518func TestFastVsFullChains(t *testing.T) {519 // Configure and generate a sample block chain520 var (521 gendb, _ = ethdb.NewMemDatabase()522 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")523 address = crypto.PubkeyToAddress(key.PublicKey)524 funds = big.NewInt(1000000000)525 gspec = &Genesis{526 Config: params.TestChainConfig,527 Alloc: GenesisAlloc{address: {Balance: funds}},528 }529 genesis = gspec.MustCommit(gendb)530 signer = types.NewEIP155Signer(gspec.Config.ChainId)531 )532 blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) {533 block.SetCoinbase(common.Address{0x00})534 // If the block number is multiple of 3, send a few bonus transactions to the miner535 if i%3 == 2 {536 for j := 0; j < i%4+1; j++ {537 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key)538 if err != nil {539 panic(err)540 }541 block.AddTx(tx)542 }543 }544 // If the block number is a multiple of 5, add a few bonus uncles to the block545 if i%5 == 5 {546 block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))})547 }548 })549 // Import the chain as an archive node for the comparison baseline550 archiveDb, _ := ethdb.NewMemDatabase()551 gspec.MustCommit(archiveDb)552 archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{})553 defer archive.Stop()554 if n, err := archive.InsertChain(blocks); err != nil {555 t.Fatalf("failed to process block %d: %v", n, err)556 }557 // Fast import the chain as a non-archive node to test558 fastDb, _ := ethdb.NewMemDatabase()559 gspec.MustCommit(fastDb)560 fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{})561 defer fast.Stop()562 headers := make([]*types.Header, len(blocks))563 for i, block := range blocks {564 headers[i] = block.Header()565 }566 if n, err := fast.InsertHeaderChain(headers, 1); err != nil {567 t.Fatalf("failed to insert header %d: %v", n, err)568 }569 if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil {570 t.Fatalf("failed to insert receipt %d: %v", n, err)571 }572 // Iterate over all chain data components, and cross reference573 for i := 0; i < len(blocks); i++ {574 num, hash := blocks[i].NumberU64(), blocks[i].Hash()575 if ftd, atd := fast.GetTdByHash(hash), archive.GetTdByHash(hash); ftd.Cmp(atd) != 0 {576 t.Errorf("block #%d [%x]: td mismatch: have %v, want %v", num, hash, ftd, atd)577 }578 if fheader, aheader := fast.GetHeaderByHash(hash), archive.GetHeaderByHash(hash); fheader.Hash() != aheader.Hash() {579 t.Errorf("block #%d [%x]: header mismatch: have %v, want %v", num, hash, fheader, aheader)580 }581 if fblock, ablock := fast.GetBlockByHash(hash), archive.GetBlockByHash(hash); fblock.Hash() != ablock.Hash() {582 t.Errorf("block #%d [%x]: block mismatch: have %v, want %v", num, hash, fblock, ablock)583 } else if types.DeriveSha(fblock.Transactions()) != types.DeriveSha(ablock.Transactions()) {584 t.Errorf("block #%d [%x]: transactions mismatch: have %v, want %v", num, hash, fblock.Transactions(), ablock.Transactions())585 } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) {586 t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles())587 }588 if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) {589 t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts)590 }591 }592 // Check that the canonical chains are the same between the databases593 for i := 0; i < len(blocks)+1; i++ {594 if fhash, ahash := GetCanonicalHash(fastDb, uint64(i)), GetCanonicalHash(archiveDb, uint64(i)); fhash != ahash {595 t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash)596 }597 }598}599// Tests that various import methods move the chain head pointers to the correct600// positions.601func TestLightVsFastVsFullChainHeads(t *testing.T) {602 // Configure and generate a sample block chain603 var (604 gendb, _ = ethdb.NewMemDatabase()605 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")606 address = crypto.PubkeyToAddress(key.PublicKey)607 funds = big.NewInt(1000000000)608 gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}}609 genesis = gspec.MustCommit(gendb)610 )611 height := uint64(1024)612 blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil)613 // Configure a subchain to roll back614 remove := []common.Hash{}615 for _, block := range blocks[height/2:] {616 remove = append(remove, block.Hash())617 }618 // Create a small assertion method to check the three heads619 assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) {620 if num := chain.CurrentBlock().NumberU64(); num != block {621 t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block)622 }623 if num := chain.CurrentFastBlock().NumberU64(); num != fast {624 t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast)625 }626 if num := chain.CurrentHeader().Number.Uint64(); num != header {627 t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header)628 }629 }630 // Import the chain as an archive node and ensure all pointers are updated631 archiveDb, _ := ethdb.NewMemDatabase()632 gspec.MustCommit(archiveDb)633 archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), vm.Config{})634 if n, err := archive.InsertChain(blocks); err != nil {635 t.Fatalf("failed to process block %d: %v", n, err)636 }637 defer archive.Stop()638 assert(t, "archive", archive, height, height, height)639 archive.Rollback(remove)640 assert(t, "archive", archive, height/2, height/2, height/2)641 // Import the chain as a non-archive node and ensure all pointers are updated642 fastDb, _ := ethdb.NewMemDatabase()643 gspec.MustCommit(fastDb)644 fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), vm.Config{})645 defer fast.Stop()646 headers := make([]*types.Header, len(blocks))647 for i, block := range blocks {648 headers[i] = block.Header()649 }650 if n, err := fast.InsertHeaderChain(headers, 1); err != nil {651 t.Fatalf("failed to insert header %d: %v", n, err)652 }653 if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil {654 t.Fatalf("failed to insert receipt %d: %v", n, err)655 }656 assert(t, "fast", fast, height, height, 0)657 fast.Rollback(remove)658 assert(t, "fast", fast, height/2, height/2, 0)659 // Import the chain as a light node and ensure all pointers are updated660 lightDb, _ := ethdb.NewMemDatabase()661 gspec.MustCommit(lightDb)662 light, _ := NewBlockChain(lightDb, gspec.Config, ethash.NewFaker(), vm.Config{})663 if n, err := light.InsertHeaderChain(headers, 1); err != nil {664 t.Fatalf("failed to insert header %d: %v", n, err)665 }666 defer light.Stop()667 assert(t, "light", light, height, 0, 0)668 light.Rollback(remove)669 assert(t, "light", light, height/2, 0, 0)670}671// Tests that chain reorganisations handle transaction removals and reinsertions.672func TestChainTxReorgs(t *testing.T) {673 var (674 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")675 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")676 key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")677 addr1 = crypto.PubkeyToAddress(key1.PublicKey)678 addr2 = crypto.PubkeyToAddress(key2.PublicKey)679 addr3 = crypto.PubkeyToAddress(key3.PublicKey)680 db, _ = ethdb.NewMemDatabase()681 gspec = &Genesis{682 Config: params.TestChainConfig,683 GasLimit: 3141592,684 Alloc: GenesisAlloc{685 addr1: {Balance: big.NewInt(1000000)},686 addr2: {Balance: big.NewInt(1000000)},687 addr3: {Balance: big.NewInt(1000000)},688 },689 }690 genesis = gspec.MustCommit(db)691 signer = types.NewEIP155Signer(gspec.Config.ChainId)692 )693 // Create two transactions shared between the chains:694 // - postponed: transaction included at a later block in the forked chain695 // - swapped: transaction included at the same block number in the forked chain696 postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)697 swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1)698 // Create two transactions that will be dropped by the forked chain:699 // - pastDrop: transaction dropped retroactively from a past block700 // - freshDrop: transaction dropped exactly at the block where the reorg is detected701 var pastDrop, freshDrop *types.Transaction702 // Create three transactions that will be added in the forked chain:703 // - pastAdd: transaction added before the reorganization is detected704 // - freshAdd: transaction added at the exact block the reorg is detected705 // - futureAdd: transaction added after the reorg has already finished706 var pastAdd, freshAdd, futureAdd *types.Transaction707 chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {708 switch i {709 case 0:710 pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)711 gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point712 gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork713 case 2:714 freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2)715 gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point716 gen.AddTx(swapped) // This transaction will be swapped out at the exact height717 gen.OffsetTime(9) // Lower the block difficulty to simulate a weaker chain718 }719 })720 // Import the chain. This runs all block validation rules.721 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{})722 if i, err := blockchain.InsertChain(chain); err != nil {723 t.Fatalf("failed to insert original chain[%d]: %v", i, err)724 }725 defer blockchain.Stop()726 // overwrite the old chain727 chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) {728 switch i {729 case 0:730 pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)731 gen.AddTx(pastAdd) // This transaction needs to be injected during reorg732 case 2:733 gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain734 gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain735 freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)736 gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time737 case 3:738 futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3)739 gen.AddTx(futureAdd) // This transaction will be added after a full reorg740 }741 })742 if _, err := blockchain.InsertChain(chain); err != nil {743 t.Fatalf("failed to insert forked chain: %v", err)744 }745 // removed tx746 for i, tx := range (types.Transactions{pastDrop, freshDrop}) {747 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {748 t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn)749 }750 if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt != nil {751 t.Errorf("drop %d: receipt %v found while shouldn't have been", i, rcpt)752 }753 }754 // added tx755 for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) {756 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {757 t.Errorf("add %d: expected tx to be found", i)758 }759 if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil {760 t.Errorf("add %d: expected receipt to be found", i)761 }762 }763 // shared tx764 for i, tx := range (types.Transactions{postponed, swapped}) {765 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil {766 t.Errorf("share %d: expected tx to be found", i)767 }768 if rcpt, _, _, _ := GetReceipt(db, tx.Hash()); rcpt == nil {769 t.Errorf("share %d: expected receipt to be found", i)770 }771 }772}773func TestLogReorgs(t *testing.T) {774 var (775 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")776 addr1 = crypto.PubkeyToAddress(key1.PublicKey)777 db, _ = ethdb.NewMemDatabase()778 // this code generates a log779 code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")780 gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}}781 genesis = gspec.MustCommit(db)782 signer = types.NewEIP155Signer(gspec.Config.ChainId)783 )784 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{})785 defer blockchain.Stop()786 rmLogsCh := make(chan RemovedLogsEvent)787 blockchain.SubscribeRemovedLogsEvent(rmLogsCh)788 chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) {789 if i == 1 {790 tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1)791 if err != nil {792 t.Fatalf("failed to create tx: %v", err)793 }794 gen.AddTx(tx)795 }796 })797 if _, err := blockchain.InsertChain(chain); err != nil {798 t.Fatalf("failed to insert chain: %v", err)799 }800 chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {})801 if _, err := blockchain.InsertChain(chain); err != nil {802 t.Fatalf("failed to insert forked chain: %v", err)803 }804 timeout := time.NewTimer(1 * time.Second)805 select {806 case ev := <-rmLogsCh:807 if len(ev.Logs) == 0 {808 t.Error("expected logs")809 }810 case <-timeout.C:811 t.Fatal("Timeout. There is no RemovedLogsEvent has been sent.")812 }813}814func TestReorgSideEvent(t *testing.T) {815 var (816 db, _ = ethdb.NewMemDatabase()817 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")818 addr1 = crypto.PubkeyToAddress(key1.PublicKey)819 gspec = &Genesis{820 Config: params.TestChainConfig,821 Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}},822 }823 genesis = gspec.MustCommit(db)824 signer = types.NewEIP155Signer(gspec.Config.ChainId)825 )826 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), vm.Config{})827 defer blockchain.Stop()828 chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {})829 if _, err := blockchain.InsertChain(chain); err != nil {830 t.Fatalf("failed to insert chain: %v", err)831 }832 replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) {833 tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1)834 if i == 2 {835 gen.OffsetTime(-9)836 }837 if err != nil {838 t.Fatalf("failed to create tx: %v", err)839 }840 gen.AddTx(tx)841 })842 chainSideCh := make(chan ChainSideEvent, 64)843 blockchain.SubscribeChainSideEvent(chainSideCh)844 if _, err := blockchain.InsertChain(replacementBlocks); err != nil {845 t.Fatalf("failed to insert chain: %v", err)846 }847 // first two block of the secondary chain are for a brief moment considered848 // side chains because up to that point the first one is considered the849 // heavier chain.850 expectedSideHashes := map[common.Hash]bool{851 replacementBlocks[0].Hash(): true,852 replacementBlocks[1].Hash(): true,853 chain[0].Hash(): true,854 chain[1].Hash(): true,855 chain[2].Hash(): true,856 }857 i := 0858 const timeoutDura = 10 * time.Second859 timeout := time.NewTimer(timeoutDura)860done:861 for {862 select {863 case ev := <-chainSideCh:864 block := ev.Block865 if _, ok := expectedSideHashes[block.Hash()]; !ok {866 t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash())867 }868 i++869 if i == len(expectedSideHashes) {870 timeout.Stop()871 break done872 }873 timeout.Reset(timeoutDura)874 case <-timeout.C:875 t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent")876 }877 }878 // make sure no more events are fired879 select {880 case e := <-chainSideCh:881 t.Errorf("unexpected event fired: %v", e)882 case <-time.After(250 * time.Millisecond):883 }884}885// Tests if the canonical block can be fetched from the database during chain insertion.886func TestCanonicalBlockRetrieval(t *testing.T) {887 bc := newTestBlockChain(true)888 defer bc.Stop()889 chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {})890 var pend sync.WaitGroup891 pend.Add(len(chain))892 for i := range chain {893 go func(block *types.Block) {894 defer pend.Done()895 // try to retrieve a block by its canonical hash and see if the block data can be retrieved.896 for {897 ch := GetCanonicalHash(bc.chainDb, block.NumberU64())898 if ch == (common.Hash{}) {899 continue // busy wait for canonical hash to be written900 }901 if ch != block.Hash() {902 t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex())903 }904 fb := GetBlock(bc.chainDb, ch, block.NumberU64())905 if fb == nil {906 t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex())907 }908 if fb.Hash() != block.Hash() {909 t.Fatalf("invalid block hash for block %d, want %s, got %s", block.NumberU64(), block.Hash().Hex(), fb.Hash().Hex())910 }911 return912 }913 }(chain[i])914 if _, err := bc.InsertChain(types.Blocks{chain[i]}); err != nil {915 t.Fatalf("failed to insert block %d: %v", i, err)916 }917 }918 pend.Wait()919}920func TestEIP155Transition(t *testing.T) {921 // Configure and generate a sample block chain922 var (923 db, _ = ethdb.NewMemDatabase()924 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")925 address = crypto.PubkeyToAddress(key.PublicKey)926 funds = big.NewInt(1000000000)927 deleteAddr = common.Address{1}928 gspec = &Genesis{929 Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)},...
insert_common.go
Source:insert_common.go
...25 "github.com/pingcap/tidb/util/chunk"26 "github.com/pingcap/tidb/util/logutil"27 "go.uber.org/zap"28)29// InsertValues is the data to insert.30type InsertValues struct {31 baseExecutor32 rowCount uint6433 lastInsertID uint6434 hasRefCols bool35 hasExtraHandle bool36 SelectExec Executor37 Table table.Table38 Columns []*ast.ColumnName39 Lists [][]expression.Expression40 SetList []*expression.Assignment41 insertColumns []*table.Column42 allAssignmentsAreConstant bool43 // colDefaultVals is used to store casted default value.44 // Because not every insert statement needs colDefaultVals, so we will init the buffer lazily.45 colDefaultVals []defaultVal46 evalBuffer chunk.MutRow47 evalBufferTypes []*types.FieldType48 // Fill the autoID lazily to datum. This is used for being compatible with JDBC using getGeneratedKeys().49 // `insert|replace values` can guarantee consecutive autoID in a batch.50 // Other statements like `insert select from` don't guarantee consecutive autoID.51 // https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html52 lazyFillAutoID bool53}54type defaultVal struct {55 val types.Datum56 // valid indicates whether the val is evaluated. We evaluate the default value lazily.57 valid bool58}59type insertCommon interface {60 insertCommon() *InsertValues61 exec(ctx context.Context, rows [][]types.Datum) error62}63func (e *InsertValues) insertCommon() *InsertValues {64 return e65}66func (e *InsertValues) exec(ctx context.Context, rows [][]types.Datum) error {67 panic("derived should overload exec function")68}69// initInsertColumns sets the explicitly specified columns of an insert statement. There are three cases:70// There are three types of insert statements:71// 1 insert ... values(...) --> name type column72// 2 insert ... set x=y... --> set type column73// 3 insert ... (select ..) --> name type column74// See https://dev.mysql.com/doc/refman/5.7/en/insert.html75func (e *InsertValues) initInsertColumns() error {76 var cols []*table.Column77 var err error78 tableCols := e.Table.Cols()79 if len(e.SetList) > 0 {80 // Process `set` type column.81 columns := make([]string, 0, len(e.SetList))82 for _, v := range e.SetList {83 columns = append(columns, v.ColName.O)84 }85 cols, err = table.FindCols(tableCols, columns, e.Table.Meta().PKIsHandle)86 if err != nil {87 return errors.Errorf("INSERT INTO %s: %s", e.Table.Meta().Name.O, err)88 }89 if len(cols) == 0 {90 return errors.Errorf("INSERT INTO %s: empty column", e.Table.Meta().Name.O)91 }92 } else if len(e.Columns) > 0 {93 // Process `name` type column.94 columns := make([]string, 0, len(e.Columns))95 for _, v := range e.Columns {96 columns = append(columns, v.Name.O)97 }98 cols, err = table.FindCols(tableCols, columns, e.Table.Meta().PKIsHandle)99 if err != nil {100 return errors.Errorf("INSERT INTO %s: %s", e.Table.Meta().Name.O, err)101 }102 } else {103 // If e.Columns are empty, use all columns instead.104 cols = tableCols105 }106 for _, col := range cols {107 e.insertColumns = append(e.insertColumns, col)108 if col.Name.L == model.ExtraHandleName.L {109 if !e.ctx.GetSessionVars().AllowWriteRowID {110 return errors.Errorf("insert, update and replace statements for _tidb_rowid are not supported.")111 }112 e.hasExtraHandle = true113 break114 }115 }116 // Check column whether is specified only once.117 err = table.CheckOnce(cols)118 if err != nil {119 return err120 }121 return nil122}123func (e *InsertValues) initEvalBuffer() {124 numCols := len(e.Table.Cols())125 if e.hasExtraHandle {126 numCols++127 }128 e.evalBufferTypes = make([]*types.FieldType, numCols)129 for i, col := range e.Table.Cols() {130 e.evalBufferTypes[i] = &col.FieldType131 }132 if e.hasExtraHandle {133 e.evalBufferTypes[len(e.evalBufferTypes)-1] = types.NewFieldType(mysql.TypeLonglong)134 }135 e.evalBuffer = chunk.MutRowFromTypes(e.evalBufferTypes)136}137func (e *InsertValues) lazilyInitColDefaultValBuf() (ok bool) {138 if e.colDefaultVals != nil {139 return true140 }141 // only if values count of insert statement is more than one, use colDefaultVals to store142 // casted default values has benefits.143 if len(e.Lists) > 1 {144 e.colDefaultVals = make([]defaultVal, len(e.Table.Cols()))145 return true146 }147 return false148}149func (e *InsertValues) processSetList() error {150 if len(e.SetList) > 0 {151 if len(e.Lists) > 0 {152 return errors.Errorf("INSERT INTO %s: set type should not use values", e.Table)153 }154 l := make([]expression.Expression, 0, len(e.SetList))155 for _, v := range e.SetList {156 l = append(l, v.Expr)157 }158 e.Lists = append(e.Lists, l)159 }160 return nil161}162// insertRows processes `insert|replace into values ()` or `insert|replace into set x=y`163func insertRows(ctx context.Context, base insertCommon) (err error) {164 e := base.insertCommon()165 // For `insert|replace into set x=y`, process the set list here.166 if err = e.processSetList(); err != nil {167 return err168 }169 e.lazyFillAutoID = true170 evalRowFunc := e.fastEvalRow171 if !e.allAssignmentsAreConstant {172 evalRowFunc = e.evalRow173 }174 rows := make([][]types.Datum, 0, len(e.Lists))175 for i, list := range e.Lists {176 e.rowCount++177 var row []types.Datum178 row, err = evalRowFunc(ctx, list, i)179 if err != nil {180 return err181 }182 rows = append(rows, row)183 }184 // Fill the batch allocated autoIDs.185 rows, err = e.lazyAdjustAutoIncrementDatum(ctx, rows)186 if err != nil {187 return err188 }189 return base.exec(ctx, rows)190}191func (e *InsertValues) handleErr(col *table.Column, val *types.Datum, rowIdx int, err error) error {192 if err == nil {193 return nil194 }195 // Convert the error with full messages.196 var (197 colTp byte198 colName string199 )200 if col != nil {201 colTp = col.Tp202 colName = col.Name.String()203 }204 if types.ErrDataTooLong.Equal(err) {205 err = resetErrDataTooLong(colName, rowIdx+1, err)206 } else if types.ErrOverflow.Equal(err) {207 err = types.ErrWarnDataOutOfRange.GenWithStackByArgs(colName, rowIdx+1)208 } else if types.ErrTruncated.Equal(err) || types.ErrTruncatedWrongVal.Equal(err) {209 valStr, err1 := val.ToString()210 if err1 != nil {211 logutil.BgLogger().Warn("truncate value failed", zap.Error(err1))212 }213 err = table.ErrTruncatedWrongValueForField.GenWithStackByArgs(types.TypeStr(colTp), valStr, colName, rowIdx+1)214 }215 return err216}217// evalRow evaluates a to-be-inserted row. The value of the column may base on another column,218// so we use setValueForRefColumn to fill the empty row some default values when needFillDefaultValues is true.219func (e *InsertValues) evalRow(ctx context.Context, list []expression.Expression, rowIdx int) ([]types.Datum, error) {220 rowLen := len(e.Table.Cols())221 if e.hasExtraHandle {222 rowLen++223 }224 row := make([]types.Datum, rowLen)225 hasValue := make([]bool, rowLen)226 // For statements like `insert into t set a = b + 1`.227 if e.hasRefCols {228 if err := e.setValueForRefColumn(row, hasValue); err != nil {229 return nil, err230 }231 }232 e.evalBuffer.SetDatums(row...)233 for i, expr := range list {234 val, err := expr.Eval(e.evalBuffer.ToRow())235 if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {236 return nil, err237 }238 val1, err := table.CastValue(e.ctx, val, e.insertColumns[i].ToInfo())239 if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {240 return nil, err241 }242 offset := e.insertColumns[i].Offset243 row[offset], hasValue[offset] = *val1.Copy(), true244 e.evalBuffer.SetDatum(offset, val1)245 }246 // Row may lack of generated column, autoIncrement column, empty column here.247 return e.fillRow(ctx, row, hasValue)248}249var emptyRow chunk.Row250func (e *InsertValues) fastEvalRow(ctx context.Context, list []expression.Expression, rowIdx int) ([]types.Datum, error) {251 rowLen := len(e.Table.Cols())252 if e.hasExtraHandle {253 rowLen++254 }255 row := make([]types.Datum, rowLen)256 hasValue := make([]bool, rowLen)257 for i, expr := range list {258 con := expr.(*expression.Constant)259 val, err := con.Eval(emptyRow)260 if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {261 return nil, err262 }263 val1, err := table.CastValue(e.ctx, val, e.insertColumns[i].ToInfo())264 if err = e.handleErr(e.insertColumns[i], &val, rowIdx, err); err != nil {265 return nil, err266 }267 offset := e.insertColumns[i].Offset268 row[offset], hasValue[offset] = val1, true269 }270 return e.fillRow(ctx, row, hasValue)271}272// setValueForRefColumn set some default values for the row to eval the row value with other columns,273// it follows these rules:274// 1. for nullable and no default value column, use NULL.275// 2. for nullable and have default value column, use it's default value.276// 3. for not null column, use zero value even in strict mode.277// 4. for auto_increment column, use zero value.278// 5. for generated column, use NULL.279func (e *InsertValues) setValueForRefColumn(row []types.Datum, hasValue []bool) error {280 for i, c := range e.Table.Cols() {281 d, err := e.getColDefaultValue(i, c)282 if err == nil {283 row[i] = d284 if !mysql.HasAutoIncrementFlag(c.Flag) {285 // It is an interesting behavior in MySQL.286 // If the value of auto ID is not explicit, MySQL use 0 value for auto ID when it is287 // evaluated by another column, but it should be used once only.288 // When we fill it as an auto ID column, it should be set as it used to be.289 // So just keep `hasValue` false for auto ID, and the others set true.290 hasValue[c.Offset] = true291 }292 } else if table.ErrNoDefaultValue.Equal(err) {293 row[i] = table.GetZeroValue(c.ToInfo())294 hasValue[c.Offset] = false295 } else if e.handleErr(c, &d, 0, err) != nil {296 return err297 }298 }299 return nil300}301func insertRowsFromSelect(ctx context.Context, base insertCommon) error {302 // process `insert|replace into ... select ... from ...`303 e := base.insertCommon()304 selectExec := e.children[0]305 fields := retTypes(selectExec)306 chk := newFirstChunk(selectExec)307 iter := chunk.NewIterator4Chunk(chk)308 rows := make([][]types.Datum, 0, chk.Capacity())309 sessVars := e.ctx.GetSessionVars()310 if !sessVars.StrictSQLMode {311 // If StrictSQLMode is disabled and it is a insert-select statement, it also handle BadNullAsWarning.312 sessVars.StmtCtx.BadNullAsWarning = true313 }314 for {315 err := Next(ctx, selectExec, chk)316 if err != nil {317 return err318 }319 if chk.NumRows() == 0 {320 break321 }322 for innerChunkRow := iter.Begin(); innerChunkRow != iter.End(); innerChunkRow = iter.Next() {323 innerRow := innerChunkRow.GetDatumRow(fields)324 e.rowCount++325 row, err := e.getRow(ctx, innerRow)326 if err != nil {327 return err328 }329 rows = append(rows, row)330 }331 err = base.exec(ctx, rows)332 if err != nil {333 return err334 }335 rows = rows[:0]336 }337 return nil338}339// getRow gets the row which from `insert into select from` or `load data`.340// The input values from these two statements are datums instead of341// expressions which are used in `insert into set x=y`.342func (e *InsertValues) getRow(ctx context.Context, vals []types.Datum) ([]types.Datum, error) {343 row := make([]types.Datum, len(e.Table.Cols()))344 hasValue := make([]bool, len(e.Table.Cols()))345 for i, v := range vals {346 casted, err := table.CastValue(e.ctx, v, e.insertColumns[i].ToInfo())347 if e.handleErr(nil, &v, 0, err) != nil {348 return nil, err349 }350 offset := e.insertColumns[i].Offset351 row[offset] = casted352 hasValue[offset] = true353 }354 return e.fillRow(ctx, row, hasValue)355}356// getColDefaultValue gets the column default value.357func (e *InsertValues) getColDefaultValue(idx int, col *table.Column) (d types.Datum, err error) {358 if e.colDefaultVals != nil && e.colDefaultVals[idx].valid {359 return e.colDefaultVals[idx].val, nil360 }361 defaultVal, err := table.GetColDefaultValue(e.ctx, col.ToInfo())362 if err != nil {363 return types.Datum{}, err364 }365 if initialized := e.lazilyInitColDefaultValBuf(); initialized {366 e.colDefaultVals[idx].val = defaultVal367 e.colDefaultVals[idx].valid = true368 }369 return defaultVal, nil370}371// fillColValue fills the column value if it is not set in the insert statement.372func (e *InsertValues) fillColValue(ctx context.Context, datum types.Datum, idx int, column *table.Column, hasValue bool) (types.Datum,373 error) {374 if mysql.HasAutoIncrementFlag(column.Flag) {375 if e.lazyFillAutoID {376 // Handle hasValue info in autoIncrement column previously for lazy handle.377 if !hasValue {378 datum.SetNull()379 }380 // Store the plain datum of autoIncrement column directly for lazy handle.381 return datum, nil382 }383 d, err := e.adjustAutoIncrementDatum(ctx, datum, hasValue, column)384 if err != nil {385 return types.Datum{}, err386 }387 return d, nil388 }389 if !hasValue {390 d, err := e.getColDefaultValue(idx, column)391 if e.handleErr(column, &datum, 0, err) != nil {392 return types.Datum{}, err393 }394 return d, nil395 }396 return datum, nil397}398// fillRow fills generated columns, auto_increment column and empty column.399// For NOT NULL column, it will return error or use zero value based on sql_mode.400// When lazyFillAutoID is true, fill row will lazily handle auto increment datum for lazy batch allocation.401// `insert|replace values` can guarantee consecutive autoID in a batch.402// Other statements like `insert select from` don't guarantee consecutive autoID.403// https://dev.mysql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html404func (e *InsertValues) fillRow(ctx context.Context, row []types.Datum, hasValue []bool) ([]types.Datum, error) {405 for i, c := range e.Table.Cols() {406 var err error407 // Get the default value for all no value columns, the auto increment column is different from the others.408 if row[i], err = e.fillColValue(ctx, row[i], i, c, hasValue[i]); err != nil {409 return nil, err410 }411 if !e.lazyFillAutoID || (e.lazyFillAutoID && !mysql.HasAutoIncrementFlag(c.Flag)) {412 if row[i], err = c.HandleBadNull(row[i], e.ctx.GetSessionVars().StmtCtx); err != nil {413 return nil, err414 }415 }416 }...
rbt_test.go
Source:rbt_test.go
...8 "github.com/stretchr/testify/assert"9)10func TestInsert(t *testing.T) {11 tree := New[types.Int, int]()12 // Note these tests check the state of the tree after an insertion using an in order traversal. The state of the tree should13 // correspond to the results obtained by doing the operations by hand.14 assert.Equal(t, true, tree.Empty())15 assert.Equal(t, "", fmt.Sprint(tree))16 tree.Insert(20, 1)17 assert.Equal(t, "20(B)", fmt.Sprint(tree))18 tree.Insert(30, 1)19 assert.Equal(t, "20(B) 30(R)", fmt.Sprint(tree))20 tree.Insert(40, 1)21 assert.Equal(t, "20(R) 30(B) 40(R)", fmt.Sprint(tree))22 tree.Insert(10, 1)23 assert.Equal(t, "10(R) 20(B) 30(B) 40(B)", fmt.Sprint(tree))24 tree.Insert(15, 1)25 assert.Equal(t, "10(R) 15(B) 20(R) 30(B) 40(B)", fmt.Sprint(tree))26 tree.Insert(25, 2)...
insert
Using AI Code Generation
1import (2func main() {3 a.Insert(1, 0)4 a.Insert(2, 1)5 a.Insert(3, 2)6 a.Insert(4, 3)7 a.Insert(5, 4)8 a.Insert(6, 5)9 a.Insert(7, 6)10 a.Insert(8, 7)11 a.Insert(9, 8)12 fmt.Println(a)13}
insert
Using AI Code Generation
1import (2func main() {3 a.insert(1)4 a.insert(2)5 a.insert(3)6 a.insert(4)7 a.insert(5)8 fmt.Println(a)9}10import (11func main() {12 a.insert(1)13 a.insert(2)14 a.insert(3)15 a.insert(4)16 a.insert(5)17 fmt.Println(a)18}19import (20func main() {21 a.insert(1)22 a.insert(2)23 a.insert(3)24 a.insert(4)25 a.insert(5)26 fmt.Println(a)27}28import (29func main() {30 a.insert(1)31 a.insert(2)32 a.insert(3)33 a.insert(4)34 a.insert(5)35 fmt.Println(a)36}37import (38func main() {39 a.insert(1)40 a.insert(2)41 a.insert(3)42 a.insert(4)43 a.insert(5)44 fmt.Println(a)45}46import (47func main() {48 a.insert(1)49 a.insert(2)50 a.insert(3)51 a.insert(4)52 a.insert(5)53 fmt.Println(a)54}55import (56func main() {57 a.insert(1)58 a.insert(2)59 a.insert(3)60 a.insert(4)61 a.insert(5)62 fmt.Println(a)63}64import (65func main() {66 a.insert(1)67 a.insert(2)68 a.insert(3)69 a.insert(4)70 a.insert(5)71 fmt.Println(a)72}
insert
Using AI Code Generation
1import "fmt"2func main(){3a.insert(5)4a.insert(10)5a.insert(15)6a.insert(20)7a.insert(25)8a.insert(30)9a.insert(35)10a.insert(40)11a.insert(45)12a.insert(50)13a.insert(55)14a.insert(60)15a.insert(65)16a.insert(70)17a.insert(75)18a.insert(80)19a.insert(85)20a.insert(90)21a.insert(95)22a.insert(100)23a.insert(105)24a.insert(110)25a.insert(115)26a.insert(120)27a.insert(125)28a.insert(130)29a.insert(135)30a.insert(140)31a.insert(145)32a.insert(150)33a.insert(155)34a.insert(160)35a.insert(165)36a.insert(170)37a.insert(175)38a.insert(180)39a.insert(185)40a.insert(190)41a.insert(195)42a.insert(200)43a.insert(205)44a.insert(210)45a.insert(215)46a.insert(220)47a.insert(225)48a.insert(230)49a.insert(235)50a.insert(240)51a.insert(245)52a.insert(250)53a.insert(255)54a.insert(260)55a.insert(265)56a.insert(270)57a.insert(275)58a.insert(280)59a.insert(285)60a.insert(290)61a.insert(295)62a.insert(300)63a.insert(305)64a.insert(310)65a.insert(315)66a.insert(320)67a.insert(325)68a.insert(330)69a.insert(335)70a.insert(340)71a.insert(345)72a.insert(350)73a.insert(355)74a.insert(360)75a.insert(365)76a.insert(370)77a.insert(375)78a.insert(380)79a.insert(385)80a.insert(390)81a.insert(395)82a.insert(400)83a.insert(405)84a.insert(410)85a.insert(415)86a.insert(420)87a.insert(425)88a.insert(430)89a.insert(435)90a.insert(440)91a.insert(445)92a.insert(450)93a.insert(455)94a.insert(460)95a.insert(465)96a.insert(470)97a.insert(475)98a.insert(480)99a.insert(485
insert
Using AI Code Generation
1import (2func main() {3 a.Insert(10)4 fmt.Println(a)5}6import (7func main() {8 a.Insert(10)9 fmt.Println(a)10}11{10}12{10}
insert
Using AI Code Generation
1import (2func main() {3 a.insert(10, 20)4 a.print()5}6import (7func main() {8 a.insert(10, 20)9 a.print()10}11import (12func main() {13 a.insert(10, 20)14 a.print()15}16import (17func main() {18 a.insert(10, 20)19 a.print()20}21import (22func main() {23 a.insert(10, 20)24 a.print()25}26import (27func main() {28 a.insert(10, 20)29 a.print()30}31import (32func main() {33 a.insert(10, 20)34 a.print()35}36import (37func main() {38 a.insert(10, 20)39 a.print()40}41import (42func main() {43 a.insert(10, 20)44 a.print()45}
insert
Using AI Code Generation
1import (2func main() {3 fmt.Println("Enter the two numbers:")4 fmt.Scan(&a, &b)5 fmt.Println("The sum of the numbers is", a+b)6}7import (8func main() {9 fmt.Println("Enter the two numbers:")10 fmt.Scan(&a, &b)11 fmt.Println("The product of the numbers is", a*b)12}13import (14func main() {15 fmt.Println("Enter the two numbers:")16 fmt.Scan(&a, &b)17 fmt.Println("The difference of the numbers is", a-b)18}19import (20func main() {21 fmt.Println("Enter the two numbers:")22 fmt.Scan(&a, &b)23 fmt.Println("The division of the numbers is", a/b)24}25import (26func main() {27 fmt.Println("Enter the two numbers:")28 fmt.Scan(&a, &b)29 fmt.Println("The modulus of the numbers is", a%b)30}31import (32func main() {33 fmt.Println("Enter the two numbers:")34 fmt.Scan(&a, &b)35 fmt.Println("The greater number is", a>b)36}37import (38func main() {39 fmt.Println("Enter the two numbers:")40 fmt.Scan(&a, &b)41 fmt.Println("The less number is", a<b)42}43import (44func main() {45 fmt.Println("Enter the two numbers:")46 fmt.Scan(&a, &b)47 fmt.Println("The
insert
Using AI Code Generation
1import (2func main() {3 slice := types.Slice{1, 2, 3, 4, 5}4 slice.Insert(2, 6)5 fmt.Println(slice)6}7func (s *Slice) Insert(index int, value int) {8 *s = append(*s, 0)9 copy((*s)[index+1:], (*s)[index:])10 (*s)[index] = value11}
insert
Using AI Code Generation
1import (2func main() {3 s := types.Student{4 }5 types.Insert(s)6}7import (8func main() {9 s := types.Student{10 }11 types.Insert(s)12}13main.main()14import (15type Student struct {16}17var (18func Insert(s Student) {19 mutex.Lock()20 slice = append(slice, s)21 mutex.Unlock()22}23import (24func main() {25 s := types.Student{26 }27 types.Insert(s)28}29import (
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!