github.com/aquanetwork/aquachain@v1.7.8/core/database_util_test.go (about)

     1  // Copyright 2015 The aquachain Authors
     2  // This file is part of the aquachain library.
     3  //
     4  // The aquachain library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The aquachain library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the aquachain library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"bytes"
    21  	"math/big"
    22  	"testing"
    23  
    24  	"gitlab.com/aquachain/aquachain/aquadb"
    25  	"gitlab.com/aquachain/aquachain/common"
    26  	"gitlab.com/aquachain/aquachain/core/types"
    27  	"gitlab.com/aquachain/aquachain/crypto"
    28  	"gitlab.com/aquachain/aquachain/crypto/sha3"
    29  	"gitlab.com/aquachain/aquachain/params"
    30  	"gitlab.com/aquachain/aquachain/rlp"
    31  )
    32  
    33  // Tests block header storage and retrieval operations.
    34  func TestHeaderStorage(t *testing.T) {
    35  	db := aquadb.NewMemDatabase()
    36  
    37  	// Create a test header to move around the database and make sure it's really new
    38  	header := &types.Header{Number: big.NewInt(2), Extra: []byte("test header")}
    39  	header.Version = params.TestChainConfig.GetBlockVersion(header.Number)
    40  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry != nil {
    41  		t.Fatalf("Non existent header returned: %v", entry)
    42  	}
    43  	// Write and verify the header in the database
    44  	if err := WriteHeader(db, header); err != nil {
    45  		t.Fatalf("Failed to write header into database: %v", err)
    46  	}
    47  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry == nil {
    48  
    49  		t.Fatalf("Stored header not found")
    50  	} else if entry.SetVersion(byte(header.Version)) != header.Hash() {
    51  		t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header)
    52  	}
    53  	if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
    54  		t.Fatalf("Stored header RLP not found")
    55  	} else {
    56  
    57  		hasher := sha3.NewKeccak256()
    58  		hasher.Write(entry)
    59  
    60  		if hash := common.BytesToHash(hasher.Sum(nil)); hash != header.Hash() {
    61  			t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
    62  		}
    63  	}
    64  	// Delete the header and verify the execution
    65  	DeleteHeader(db, header.Hash(), header.Number.Uint64())
    66  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry != nil {
    67  		t.Fatalf("Deleted header returned: %v", entry)
    68  	}
    69  }
    70  
    71  // Tests block header storage and retrieval operations.
    72  func TestHeaderStorageArgon(t *testing.T) {
    73  	db := aquadb.NewMemDatabase()
    74  
    75  	// Create a test header to move around the database and make sure it's really new
    76  	header := &types.Header{Number: big.NewInt(6), Extra: []byte("test header")}
    77  	header.Version = params.TestChainConfig.GetBlockVersion(header.Number)
    78  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry != nil {
    79  		t.Fatalf("Non existent header returned: %v", entry)
    80  	}
    81  	// Write and verify the header in the database
    82  	if err := WriteHeader(db, header); err != nil {
    83  		t.Fatalf("Failed to write header into database: %v", err)
    84  	}
    85  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry == nil {
    86  
    87  		t.Fatalf("Stored header not found")
    88  	} else if entry.SetVersion(byte(header.Version)) != header.Hash() {
    89  		t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, header)
    90  	}
    91  	if entry := GetHeaderRLP(db, header.Hash(), header.Number.Uint64()); entry == nil {
    92  		t.Fatalf("Stored header RLP not found")
    93  	} else {
    94  		if hash := common.BytesToHash(crypto.VersionHash(byte(header.Version), entry)); hash != header.Hash() {
    95  			t.Fatalf("Retrieved RLP header mismatch: have %v, want %v", entry, header)
    96  		}
    97  	}
    98  	// Delete the header and verify the execution
    99  	DeleteHeader(db, header.Hash(), header.Number.Uint64())
   100  	if entry := GetHeaderNoVersion(db, header.Hash(), header.Number.Uint64()); entry != nil {
   101  		t.Fatalf("Deleted header returned: %v", entry)
   102  	}
   103  }
   104  
   105  // Tests block body storage and retrieval operations.
   106  func TestBodyStorage(t *testing.T) {
   107  	db := aquadb.NewMemDatabase()
   108  
   109  	// Create a test body to move around the database and make sure it's really new
   110  	body := &types.Body{Uncles: []*types.Header{{Extra: []byte("test header")}}}
   111  
   112  	hasher := sha3.NewKeccak256()
   113  	rlp.Encode(hasher, body)
   114  	hash := common.BytesToHash(hasher.Sum(nil))
   115  
   116  	if entry := GetBodyNoVersion(db, hash, 0); entry != nil {
   117  		t.Fatalf("Non existent body returned: %v", entry)
   118  	}
   119  	// Write and verify the body in the database
   120  	if err := WriteBody(db, hash, 0, body); err != nil {
   121  		t.Fatalf("Failed to write body into database: %v", err)
   122  	}
   123  	if entry := GetBodyNoVersion(db, hash, 0); entry == nil {
   124  		t.Fatalf("Stored body not found")
   125  	} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(types.Transactions(body.Transactions)) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(body.Uncles) {
   126  		t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, body)
   127  	}
   128  	if entry := GetBodyRLP(db, hash, 0); entry == nil {
   129  		t.Fatalf("Stored body RLP not found")
   130  	} else {
   131  		hasher := sha3.NewKeccak256()
   132  		hasher.Write(entry)
   133  
   134  		if calc := common.BytesToHash(hasher.Sum(nil)); calc != hash {
   135  			t.Fatalf("Retrieved RLP body mismatch: have %v, want %v", entry, body)
   136  		}
   137  	}
   138  	// Delete the body and verify the execution
   139  	DeleteBody(db, hash, 0)
   140  	if entry := GetBodyNoVersion(db, hash, 0); entry != nil {
   141  		t.Fatalf("Deleted body returned: %v", entry)
   142  	}
   143  }
   144  
   145  // Tests block storage and retrieval operations.
   146  func TestBlockStorage(t *testing.T) {
   147  	db := aquadb.NewMemDatabase()
   148  
   149  	// Create a test block to move around the database and make sure it's really new
   150  	block := types.NewBlockWithHeader(&types.Header{
   151  		Extra:       []byte("test block"),
   152  		UncleHash:   types.EmptyUncleHash,
   153  		TxHash:      types.EmptyRootHash,
   154  		ReceiptHash: types.EmptyRootHash,
   155  		Version:     1,
   156  	})
   157  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   158  		t.Fatalf("Non existent block returned: %v", entry)
   159  	}
   160  	if entry := GetHeaderNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   161  		t.Fatalf("Non existent header returned: %v", entry)
   162  	}
   163  	if entry := GetBodyNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   164  		t.Fatalf("Non existent body returned: %v", entry)
   165  	}
   166  	// Write and verify the block in the database
   167  	if err := WriteBlock(db, block); err != nil {
   168  		t.Fatalf("Failed to write block into database: %v", err)
   169  	}
   170  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry == nil {
   171  		t.Fatalf("Stored block not found")
   172  	} else if entry.SetVersion(block.Version()) != block.Hash() {
   173  		t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
   174  	}
   175  	if entry := GetHeaderNoVersion(db, block.Hash(), block.NumberU64()); entry == nil {
   176  		t.Fatalf("Stored header not found")
   177  	} else if entry.SetVersion(byte(block.Version())) != block.Header().Hash() {
   178  		t.Fatalf("Retrieved header mismatch: have %v, want %v", entry, block.Header())
   179  	}
   180  	if entry := GetBodyNoVersion(db, block.Hash(), block.NumberU64()); entry == nil {
   181  		t.Fatalf("Stored body not found")
   182  	} else if types.DeriveSha(types.Transactions(entry.Transactions)) != types.DeriveSha(block.Transactions()) || types.CalcUncleHash(entry.Uncles) != types.CalcUncleHash(block.Uncles()) {
   183  		t.Fatalf("Retrieved body mismatch: have %v, want %v", entry, block.Body())
   184  	}
   185  	// Delete the block and verify the execution
   186  	DeleteBlock(db, block.Hash(), block.NumberU64())
   187  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   188  		t.Fatalf("Deleted block returned: %v", entry)
   189  	}
   190  	if entry := GetHeaderNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   191  		t.Fatalf("Deleted header returned: %v", entry)
   192  	}
   193  	if entry := GetBodyNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   194  		t.Fatalf("Deleted body returned: %v", entry)
   195  	}
   196  }
   197  
   198  // Tests that partial block contents don't get reassembled into full blocks.
   199  func TestPartialBlockStorage(t *testing.T) {
   200  	db := aquadb.NewMemDatabase()
   201  	block := types.NewBlockWithHeader(&types.Header{
   202  		Extra:       []byte("test block"),
   203  		UncleHash:   types.EmptyUncleHash,
   204  		TxHash:      types.EmptyRootHash,
   205  		ReceiptHash: types.EmptyRootHash,
   206  		Version:     1,
   207  	})
   208  	// Store a header and check that it's not recognized as a block
   209  	if err := WriteHeader(db, block.Header()); err != nil {
   210  		t.Fatalf("Failed to write header into database: %v", err)
   211  	}
   212  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   213  		t.Fatalf("Non existent block returned: %v", entry)
   214  	}
   215  	DeleteHeader(db, block.Hash(), block.NumberU64())
   216  
   217  	// Store a body and check that it's not recognized as a block
   218  	if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
   219  		t.Fatalf("Failed to write body into database: %v", err)
   220  	}
   221  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry != nil {
   222  		t.Fatalf("Non existent block returned: %v", entry)
   223  	}
   224  	DeleteBody(db, block.Hash(), block.NumberU64())
   225  
   226  	// Store a header and a body separately and check reassembly
   227  	if err := WriteHeader(db, block.Header()); err != nil {
   228  		t.Fatalf("Failed to write header into database: %v", err)
   229  	}
   230  	if err := WriteBody(db, block.Hash(), block.NumberU64(), block.Body()); err != nil {
   231  		t.Fatalf("Failed to write body into database: %v", err)
   232  	}
   233  	if entry := GetBlockNoVersion(db, block.Hash(), block.NumberU64()); entry == nil {
   234  		t.Fatalf("Stored block not found")
   235  	} else if entry.SetVersion(block.Version()) != block.Hash() {
   236  		t.Fatalf("Retrieved block mismatch: have %v, want %v", entry, block)
   237  	}
   238  }
   239  
   240  // Tests block total difficulty storage and retrieval operations.
   241  func TestTdStorage(t *testing.T) {
   242  	db := aquadb.NewMemDatabase()
   243  
   244  	// Create a test TD to move around the database and make sure it's really new
   245  	hash, td := common.Hash{}, big.NewInt(314)
   246  	if entry := GetTd(db, hash, 0); entry != nil {
   247  		t.Fatalf("Non existent TD returned: %v", entry)
   248  	}
   249  	// Write and verify the TD in the database
   250  	if err := WriteTd(db, hash, 0, td); err != nil {
   251  		t.Fatalf("Failed to write TD into database: %v", err)
   252  	}
   253  	if entry := GetTd(db, hash, 0); entry == nil {
   254  		t.Fatalf("Stored TD not found")
   255  	} else if entry.Cmp(td) != 0 {
   256  		t.Fatalf("Retrieved TD mismatch: have %v, want %v", entry, td)
   257  	}
   258  	// Delete the TD and verify the execution
   259  	DeleteTd(db, hash, 0)
   260  	if entry := GetTd(db, hash, 0); entry != nil {
   261  		t.Fatalf("Deleted TD returned: %v", entry)
   262  	}
   263  }
   264  
   265  // Tests that canonical numbers can be mapped to hashes and retrieved.
   266  func TestCanonicalMappingStorage(t *testing.T) {
   267  	db := aquadb.NewMemDatabase()
   268  
   269  	// Create a test canonical number and assinged hash to move around
   270  	hash, number := common.Hash{0: 0xff}, uint64(314)
   271  	if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
   272  		t.Fatalf("Non existent canonical mapping returned: %v", entry)
   273  	}
   274  	// Write and verify the TD in the database
   275  	if err := WriteCanonicalHash(db, hash, number); err != nil {
   276  		t.Fatalf("Failed to write canonical mapping into database: %v", err)
   277  	}
   278  	if entry := GetCanonicalHash(db, number); entry == (common.Hash{}) {
   279  		t.Fatalf("Stored canonical mapping not found")
   280  	} else if entry != hash {
   281  		t.Fatalf("Retrieved canonical mapping mismatch: have %v, want %v", entry, hash)
   282  	}
   283  	// Delete the TD and verify the execution
   284  	DeleteCanonicalHash(db, number)
   285  	if entry := GetCanonicalHash(db, number); entry != (common.Hash{}) {
   286  		t.Fatalf("Deleted canonical mapping returned: %v", entry)
   287  	}
   288  }
   289  
   290  // Tests that head headers and head blocks can be assigned, individually.
   291  func TestHeadStorage(t *testing.T) {
   292  	db := aquadb.NewMemDatabase()
   293  
   294  	blockHead := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block header"), Version: 1})
   295  	blockFull := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block full"), Version: 1})
   296  	blockFast := types.NewBlockWithHeader(&types.Header{Extra: []byte("test block fast"), Version: 1})
   297  
   298  	// Check that no head entries are in a pristine database
   299  	if entry := GetHeadHeaderHash(db); entry != (common.Hash{}) {
   300  		t.Fatalf("Non head header entry returned: %v", entry)
   301  	}
   302  	if entry := GetHeadBlockHash(db); entry != (common.Hash{}) {
   303  		t.Fatalf("Non head block entry returned: %v", entry)
   304  	}
   305  	if entry := GetHeadFastBlockHash(db); entry != (common.Hash{}) {
   306  		t.Fatalf("Non fast head block entry returned: %v", entry)
   307  	}
   308  	// Assign separate entries for the head header and block
   309  	if err := WriteHeadHeaderHash(db, blockHead.Hash()); err != nil {
   310  		t.Fatalf("Failed to write head header hash: %v", err)
   311  	}
   312  	if err := WriteHeadBlockHash(db, blockFull.Hash()); err != nil {
   313  		t.Fatalf("Failed to write head block hash: %v", err)
   314  	}
   315  	if err := WriteHeadFastBlockHash(db, blockFast.Hash()); err != nil {
   316  		t.Fatalf("Failed to write fast head block hash: %v", err)
   317  	}
   318  	// Check that both heads are present, and different (i.e. two heads maintained)
   319  	if entry := GetHeadHeaderHash(db); entry != blockHead.Hash() {
   320  		t.Fatalf("Head header hash mismatch: have %v, want %v", entry, blockHead.Hash())
   321  	}
   322  	if entry := GetHeadBlockHash(db); entry != blockFull.Hash() {
   323  		t.Fatalf("Head block hash mismatch: have %v, want %v", entry, blockFull.Hash())
   324  	}
   325  	if entry := GetHeadFastBlockHash(db); entry != blockFast.Hash() {
   326  		t.Fatalf("Fast head block hash mismatch: have %v, want %v", entry, blockFast.Hash())
   327  	}
   328  }
   329  
   330  // Tests that positional lookup metadata can be stored and retrieved.
   331  func TestLookupStorage(t *testing.T) {
   332  	db := aquadb.NewMemDatabase()
   333  
   334  	tx1 := types.NewTransaction(1, common.BytesToAddress([]byte{0x11}), big.NewInt(111), 1111, big.NewInt(11111), []byte{0x11, 0x11, 0x11})
   335  	tx2 := types.NewTransaction(2, common.BytesToAddress([]byte{0x22}), big.NewInt(222), 2222, big.NewInt(22222), []byte{0x22, 0x22, 0x22})
   336  	tx3 := types.NewTransaction(3, common.BytesToAddress([]byte{0x33}), big.NewInt(333), 3333, big.NewInt(33333), []byte{0x33, 0x33, 0x33})
   337  	txs := []*types.Transaction{tx1, tx2, tx3}
   338  
   339  	block := types.NewBlock(&types.Header{Number: big.NewInt(314)}, txs, nil, nil)
   340  	block.SetVersion(params.TestChainConfig.GetBlockVersion(block.Number()))
   341  	// Check that no transactions entries are in a pristine database
   342  	for i, tx := range txs {
   343  		if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
   344  			t.Fatalf("tx #%d [%x]: non existent transaction returned: %v", i, tx.Hash(), txn)
   345  		}
   346  	}
   347  	// Insert all the transactions into the database, and verify contents
   348  	if err := WriteBlock(db, block); err != nil {
   349  		t.Fatalf("failed to write block contents: %v", err)
   350  	}
   351  	if err := WriteTxLookupEntries(db, block); err != nil {
   352  		t.Fatalf("failed to write transactions: %v", err)
   353  	}
   354  	for i, tx := range txs {
   355  		if txn, hash, number, index := GetTransaction(db, tx.Hash()); txn == nil {
   356  			t.Fatalf("tx #%d [%x]: transaction not found", i, tx.Hash())
   357  		} else {
   358  			if hash != block.Hash() || number != block.NumberU64() || index != uint64(i) {
   359  				t.Fatalf("tx #%d [%x]: positional metadata mismatch: have %x/%d/%d, want %x/%v/%v", i, tx.Hash(), hash, number, index, block.Hash(), block.NumberU64(), i)
   360  			}
   361  			if tx.String() != txn.String() {
   362  				t.Fatalf("tx #%d [%x]: transaction mismatch: have %v, want %v", i, tx.Hash(), txn, tx)
   363  			}
   364  		}
   365  	}
   366  	// Delete the transactions and check purge
   367  	for i, tx := range txs {
   368  		DeleteTxLookupEntry(db, tx.Hash())
   369  		if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil {
   370  			t.Fatalf("tx #%d [%x]: deleted transaction returned: %v", i, tx.Hash(), txn)
   371  		}
   372  	}
   373  }
   374  
   375  // Tests that receipts associated with a single block can be stored and retrieved.
   376  func TestBlockReceiptStorage(t *testing.T) {
   377  	db := aquadb.NewMemDatabase()
   378  
   379  	receipt1 := &types.Receipt{
   380  		Status:            types.ReceiptStatusFailed,
   381  		CumulativeGasUsed: 1,
   382  		Logs: []*types.Log{
   383  			{Address: common.BytesToAddress([]byte{0x11})},
   384  			{Address: common.BytesToAddress([]byte{0x01, 0x11})},
   385  		},
   386  		TxHash:          common.BytesToHash([]byte{0x11, 0x11}),
   387  		ContractAddress: common.BytesToAddress([]byte{0x01, 0x11, 0x11}),
   388  		GasUsed:         111111,
   389  	}
   390  	receipt2 := &types.Receipt{
   391  		PostState:         common.Hash{2}.Bytes(),
   392  		CumulativeGasUsed: 2,
   393  		Logs: []*types.Log{
   394  			{Address: common.BytesToAddress([]byte{0x22})},
   395  			{Address: common.BytesToAddress([]byte{0x02, 0x22})},
   396  		},
   397  		TxHash:          common.BytesToHash([]byte{0x22, 0x22}),
   398  		ContractAddress: common.BytesToAddress([]byte{0x02, 0x22, 0x22}),
   399  		GasUsed:         222222,
   400  	}
   401  	receipts := []*types.Receipt{receipt1, receipt2}
   402  
   403  	// Check that no receipt entries are in a pristine database
   404  	hash := common.BytesToHash([]byte{0x03, 0x14})
   405  	if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
   406  		t.Fatalf("non existent receipts returned: %v", rs)
   407  	}
   408  	// Insert the receipt slice into the database and check presence
   409  	if err := WriteBlockReceipts(db, hash, 0, receipts); err != nil {
   410  		t.Fatalf("failed to write block receipts: %v", err)
   411  	}
   412  	if rs := GetBlockReceipts(db, hash, 0); len(rs) == 0 {
   413  		t.Fatalf("no receipts returned")
   414  	} else {
   415  		for i := 0; i < len(receipts); i++ {
   416  			rlpHave, _ := rlp.EncodeToBytes(rs[i])
   417  			rlpWant, _ := rlp.EncodeToBytes(receipts[i])
   418  
   419  			if !bytes.Equal(rlpHave, rlpWant) {
   420  				t.Fatalf("receipt #%d: receipt mismatch: have %v, want %v", i, rs[i], receipts[i])
   421  			}
   422  		}
   423  	}
   424  	// Delete the receipt slice and check purge
   425  	DeleteBlockReceipts(db, hash, 0)
   426  	if rs := GetBlockReceipts(db, hash, 0); len(rs) != 0 {
   427  		t.Fatalf("deleted receipts returned: %v", rs)
   428  	}
   429  }