return consensusResult, nil
}
+// DeleteBlock delete a new block in the protocol.
+func (s *Store) DeleteBlock(block *types.Block) error {
+ blockHash := block.Hash()
+ blockHashes, err := s.GetBlockHashesByHeight(block.Height)
+ if err != nil {
+ return err
+ }
+
+ for i := 0; i < len(blockHashes); i++ {
+ if blockHashes[i].String() == blockHash.String() {
+ blockHashes = append(blockHashes[0:i], blockHashes[i+1:len(blockHashes)]...)
+ break
+ }
+ }
+
+ batch := s.db.NewBatch()
+ if len(blockHashes) == 0 {
+ batch.Delete(calcBlockHashesPrefix(block.Height))
+ } else {
+ binaryBlockHashes, err := json.Marshal(blockHashes)
+ if err != nil {
+ return errors.Wrap(err, "Marshal block hashes")
+ }
+
+ batch.Set(calcBlockHashesPrefix(block.Height), binaryBlockHashes)
+ }
+
+ batch.Delete(calcBlockHeaderKey(&blockHash))
+ batch.Delete(calcBlockTransactionsKey(&blockHash))
+ batch.Delete(calcTxStatusKey(&blockHash))
+ batch.Write()
+
+ s.cache.removeBlockHashes(block.Height)
+ s.cache.removeBlockHeader(&block.BlockHeader)
+
+ return nil
+}
+
// NewStore creates and returns a new Store object.
func NewStore(db dbm.DB) *Store {
fillBlockHeaderFn := func(hash *bc.Hash) (*types.BlockHeader, error) {
"os"
"testing"
+ "github.com/stretchr/testify/require"
+
"github.com/bytom/vapor/consensus"
dbm "github.com/bytom/vapor/database/leveldb"
"github.com/bytom/vapor/database/storage"
}
}
}
+
+func TestDeleteBlock(t *testing.T) {
+ cases := []struct {
+ initBlocks []*types.BlockHeader
+ deleteBlock *types.BlockHeader
+ wantBlocks []*types.BlockHeader
+ }{
+ {
+ initBlocks: []*types.BlockHeader{},
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ wantBlocks: []*types.BlockHeader{},
+ },
+ {
+ initBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ },
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ wantBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ },
+ },
+ {
+ initBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ },
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ wantBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ },
+ },
+ {
+ initBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ },
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945010),
+ },
+ wantBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945005),
+ },
+ },
+ },
+ {
+ initBlocks: []*types.BlockHeader{},
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945030),
+ },
+ wantBlocks: []*types.BlockHeader{},
+ },
+ {
+ initBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ },
+ deleteBlock: &types.BlockHeader{
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945030),
+ },
+ wantBlocks: []*types.BlockHeader{
+ {
+ Version: uint64(1),
+ Height: uint64(1),
+ Timestamp: uint64(1528945000),
+ },
+ },
+ },
+ }
+
+ for _, c := range cases {
+ verifyStatus := &bc.TransactionStatus{
+ VerifyStatus: []*bc.TxVerifyResult{
+ {StatusFail: false},
+ },
+ }
+ deleteBlock := &types.Block{
+ BlockHeader: types.BlockHeader{
+ Version: c.deleteBlock.Version,
+ Height: c.deleteBlock.Height,
+ Timestamp: c.deleteBlock.Timestamp,
+ },
+ }
+
+ dbA := dbm.NewDB("dbu", "leveldb", "tempA")
+ dbB := dbm.NewDB("dbc", "leveldb", "tempB")
+
+ storeA := NewStore(dbA)
+ storeB := NewStore(dbB)
+
+ for i := 0; i < len(c.initBlocks); i++ {
+ block := &types.Block{
+ BlockHeader: types.BlockHeader{
+ Version: c.initBlocks[i].Version,
+ Height: c.initBlocks[i].Height,
+ Timestamp: c.initBlocks[i].Timestamp,
+ },
+ }
+ if err := storeA.SaveBlock(block, verifyStatus); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ if err := storeA.DeleteBlock(deleteBlock); err != nil {
+ t.Fatal(err)
+ }
+
+ for i := 0; i < len(c.wantBlocks); i++ {
+ block := &types.Block{
+ BlockHeader: types.BlockHeader{
+ Version: c.wantBlocks[i].Version,
+ Height: c.wantBlocks[i].Height,
+ Timestamp: c.wantBlocks[i].Timestamp,
+ },
+ }
+ if err := storeB.SaveBlock(block, verifyStatus); err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ iterA := dbA.Iterator()
+ iterB := dbB.Iterator()
+
+ for iterA.Next() && iterB.Next() {
+ require.Equal(t, iterA.Key(), iterB.Key())
+ require.Equal(t, iterA.Value(), iterB.Value())
+ }
+
+ if iterA.Next() || iterB.Next() {
+ t.Fatalf("why iterator is not finished")
+ }
+
+ dbA.Close()
+ os.RemoveAll("tempA")
+ dbB.Close()
+ os.RemoveAll("tempB")
+ }
+}
func (s *mockStore) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
func (s *mockStore) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
func (s *mockStore) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
+func (s *mockStore) DeleteBlock(*types.Block) error { return nil }
func (s *mockStore) SaveBlockHeader(*types.BlockHeader) error { return nil }
func (s *mockStore) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {
return nil
func (s *mockStore1) GetConsensusResult(uint64) (*state.ConsensusResult, error) { return nil, nil }
func (s *mockStore1) GetMainChainHash(uint64) (*bc.Hash, error) { return nil, nil }
func (s *mockStore1) GetBlockHashesByHeight(uint64) ([]*bc.Hash, error) { return nil, nil }
+func (s *mockStore1) DeleteBlock(*types.Block) error { return nil }
func (s *mockStore1) SaveBlock(*types.Block, *bc.TransactionStatus) error { return nil }
func (s *mockStore1) SaveBlockHeader(*types.BlockHeader) error { return nil }
func (s *mockStore1) SaveChainStatus(*types.BlockHeader, *types.BlockHeader, []*types.BlockHeader, *state.UtxoViewpoint, []*state.ConsensusResult) error {