diff --git a/blockchain/chainstoreffldb.go b/blockchain/chainstoreffldb.go index 2d81107d6..ac1f068f9 100644 --- a/blockchain/chainstoreffldb.go +++ b/blockchain/chainstoreffldb.go @@ -408,8 +408,23 @@ func (c *ChainStoreFFLDB) GetUTXO(programHash *Uint168) ([]*common.UTXO, error) return c.indexManager.FetchUTXO(programHash) } +func DBFetchTx3IndexEntry(dbTx database.Tx, txHash *Uint256) bool { + hashIndex := dbTx.Metadata().Bucket(Tx3IndexBucketName) + value := hashIndex.Get(txHash[:]) + if bytes.Equal(value, Tx3IndexValue) { + return true + } + return false +} + func (c *ChainStoreFFLDB) IsTx3Exist(txHash *Uint256) bool { - return c.indexManager.IsTx3Exist(txHash) + exist := false + _ = c.db.View(func(dbTx database.Tx) error { + exist = DBFetchTx3IndexEntry(dbTx, txHash) + return nil + }) + + return exist } func (c *ChainStoreFFLDB) IsSideChainReturnDepositExist(txHash *Uint256) bool { diff --git a/blockchain/indexers/common.go b/blockchain/indexers/common.go index d760c1334..626885701 100644 --- a/blockchain/indexers/common.go +++ b/blockchain/indexers/common.go @@ -69,9 +69,6 @@ type IndexManager interface { // FetchUTXO retrieval the utxo set of a account address FetchUTXO(programHash *common.Uint168) ([]*common2.UTXO, error) - // IsTx3Exist use to find if tx3 exist in DB - IsTx3Exist(txHash *common.Uint256) bool - // IsSideChainReturnDepositExist use to find if return deposit exist in DB IsSideChainReturnDepositExist(txHash *common.Uint256) bool } diff --git a/blockchain/indexers/manager.go b/blockchain/indexers/manager.go index 1f3ae4fe5..f5f2f3c8c 100644 --- a/blockchain/indexers/manager.go +++ b/blockchain/indexers/manager.go @@ -506,16 +506,6 @@ func (m *Manager) FetchUTXO(programHash *common.Uint168) ([]*common2.UTXO, error return utxos, nil } -func (m *Manager) IsTx3Exist(txHash *common.Uint256) bool { - exist := false - _ = m.db.View(func(dbTx database.Tx) error { - exist = DBFetchTx3IndexEntry(dbTx, txHash) - return nil - }) - - return exist -} - func (m *Manager) IsSideChainReturnDepositExist(txHash *common.Uint256) bool { exist := false _ = m.db.View(func(dbTx database.Tx) error { @@ -534,10 +524,9 @@ func NewManager(db database.DB, params *config.Params) *Manager { txIndex := NewTxIndex(db) unspentIndex := NewUnspentIndex(db, params) utxoIndex := NewUtxoIndex(db, unspentIndex) - tx3Index := NewTx3Index(db) returnDepositIndex := NewReturnDepositIndex(db) var enabledIndexes []Indexer - enabledIndexes = append(enabledIndexes, txIndex, unspentIndex, utxoIndex, tx3Index, returnDepositIndex) + enabledIndexes = append(enabledIndexes, txIndex, unspentIndex, utxoIndex, returnDepositIndex) return &Manager{ db: db, enabledIndexes: enabledIndexes, diff --git a/common/bucketname.go b/common/bucketname.go index 630c62339..14933c242 100644 --- a/common/bucketname.go +++ b/common/bucketname.go @@ -5,4 +5,11 @@ var ( // ProposalDraftDataBucketName is the name of the DB bucket used to house the // proposal releated draft data and draft hash. ProposalDraftDataBucketName = []byte("proposaldraftdata") + + // Tx3IndexBucketName is the key of the tx3 index and the DB bucket used + // to house it. + Tx3IndexBucketName = []byte("tx3hash") + + // Tx3IndexValue is placeholder for tx3 index + Tx3IndexValue = []byte{1} ) diff --git a/core/transaction/withdrawfromsidechaintransaction.go b/core/transaction/withdrawfromsidechaintransaction.go index 00b999626..611d38753 100644 --- a/core/transaction/withdrawfromsidechaintransaction.go +++ b/core/transaction/withdrawfromsidechaintransaction.go @@ -9,6 +9,7 @@ import ( "bytes" "encoding/hex" "errors" + "github.com/elastos/Elastos.ELA/database" "math" "math/big" @@ -326,3 +327,87 @@ func checkSchnorrWithdrawFromSidechain(t interfaces.Transaction, pld *payload.Wi } return nil } + +func (t *WithdrawFromSideChainTransaction) GetSaveProcessor() (database.TXProcessor, elaerr.ELAError) { + + witPayload := t.Payload().(*payload.WithdrawFromSideChain) + if t.PayloadVersion() == payload.WithdrawFromSideChainVersion { + return func(dbTx database.Tx) error { + err := blockchain.TryCreateBucket(dbTx, common.Tx3IndexBucketName) + if err != nil { + return err + } + for _, hash := range witPayload.SideChainTransactionHashes { + err = blockchain.DBPutData(dbTx, common.Tx3IndexBucketName, + hash[:], common.Tx3IndexValue) + if err != nil { + return err + } + } + + return nil + }, nil + } else if t.PayloadVersion() == payload.WithdrawFromSideChainVersionV1 { + return func(dbTx database.Tx) error { + err := blockchain.TryCreateBucket(dbTx, common.Tx3IndexBucketName) + if err != nil { + return err + } + for _, output := range t.Outputs() { + if output.Type != common2.OTWithdrawFromSideChain { + continue + } + witPayload, ok := output.Payload.(*outputpayload.Withdraw) + if !ok { + continue + } + err = blockchain.DBPutData(dbTx, common.Tx3IndexBucketName, + witPayload.SideChainTransactionHash[:], common.Tx3IndexValue) + if err != nil { + return err + } + } + + return nil + }, nil + } + + return nil, nil +} + +func (t *WithdrawFromSideChainTransaction) GetRollbackProcessor() (database.TXProcessor, elaerr.ELAError) { + + witPayload := t.Payload().(*payload.WithdrawFromSideChain) + if t.PayloadVersion() == payload.WithdrawFromSideChainVersion { + return func(dbTx database.Tx) error { + for _, hash := range witPayload.SideChainTransactionHashes { + err := blockchain.DBRemoveData(dbTx, common.Tx3IndexBucketName, hash[:]) + if err != nil { + return err + } + } + + return nil + }, nil + } else if t.PayloadVersion() == payload.WithdrawFromSideChainVersionV1 { + return func(dbTx database.Tx) error { + for _, output := range t.Outputs() { + if output.Type != common2.OTWithdrawFromSideChain { + continue + } + witPayload, ok := output.Payload.(*outputpayload.Withdraw) + if !ok { + continue + } + err := blockchain.DBRemoveData(dbTx, common.Tx3IndexBucketName, witPayload.SideChainTransactionHash[:]) + if err != nil { + return err + } + } + + return nil + }, nil + } + + return nil, nil +} diff --git a/errors/errcode_test.go b/errors/errcode_test.go index 655159d27..0796f9c4b 100644 --- a/errors/errcode_test.go +++ b/errors/errcode_test.go @@ -21,7 +21,7 @@ func TestSimple(t *testing.T) { innerErr := errors.New("inner error") err = Simple(ErrFail, innerErr) assert.Equal(t, ErrFail, err.Code()) - assert.Equal(t, ErrMap[ErrFail], err.Error()) + assert.Equal(t, ErrMap[ErrFail]+":"+innerErr.Error(), err.Error()) assert.Equal(t, innerErr, err.InnerError()) } diff --git a/errors/jsonformat_test.go b/errors/jsonformat_test.go index 489a0fe63..468f19221 100644 --- a/errors/jsonformat_test.go +++ b/errors/jsonformat_test.go @@ -21,9 +21,9 @@ func TestToJsonFormatter(t *testing.T) { formatter := ToJsonFormatter(simpleParent) assert.Equal(t, int(simpleParentCode), formatter.Code) - assert.Equal(t, ErrMap[simpleParentCode], formatter.Description) + assert.Equal(t, ErrMap[simpleParentCode]+":"+ErrMap[simpleChildCode]+":"+plainErr.Error(), formatter.Description) assert.Equal(t, int(simpleChildCode), formatter.Inner.Code) - assert.Equal(t, ErrMap[simpleChildCode], formatter.Inner.Description) + assert.Equal(t, ErrMap[simpleChildCode]+":"+plainErr.Error(), formatter.Inner.Description) assert.Equal(t, int(ErrFail), formatter.Inner.Inner.Code) assert.Equal(t, plainErr.Error(), formatter.Inner.Inner.Description) } diff --git a/test/unit/tx3index_test.go b/test/unit/tx3index_test.go deleted file mode 100644 index 61da5a265..000000000 --- a/test/unit/tx3index_test.go +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) 2017-2020 The Elastos Foundation -// Use of this source code is governed by an MIT -// license that can be found in the LICENSE file. -// - -package unit - -import ( - "testing" - - "github.com/elastos/Elastos.ELA/blockchain/indexers" - "github.com/elastos/Elastos.ELA/common" - "github.com/elastos/Elastos.ELA/common/config" - "github.com/elastos/Elastos.ELA/common/log" - "github.com/elastos/Elastos.ELA/core/contract/program" - "github.com/elastos/Elastos.ELA/core/transaction" - "github.com/elastos/Elastos.ELA/core/types" - common2 "github.com/elastos/Elastos.ELA/core/types/common" - "github.com/elastos/Elastos.ELA/core/types/functions" - "github.com/elastos/Elastos.ELA/core/types/interfaces" - "github.com/elastos/Elastos.ELA/core/types/payload" - "github.com/elastos/Elastos.ELA/database" - "github.com/elastos/Elastos.ELA/utils/test" - - "github.com/stretchr/testify/assert" -) - -func init() { - functions.GetTransactionByTxType = transaction.GetTransaction - functions.GetTransactionByBytes = transaction.GetTransactionByBytes - functions.CreateTransaction = transaction.CreateTransaction - functions.GetTransactionParameters = transaction.GetTransactionparameters - config.DefaultParams = config.GetDefaultParams() -} - -var ( - tx3Hash = common.Uint256{1, 2, 3} - - tx4 interfaces.Transaction - testTx3IndexBlock *types.Block - - testTx3Index *indexers.Tx3Index - tx3IndexDB database.DB -) - -func initIndexBlock() { - tx4 = functions.CreateTransaction( - 0, - common2.WithdrawFromSideChain, - 0, - &payload.WithdrawFromSideChain{ - SideChainTransactionHashes: []common.Uint256{ - tx3Hash, - }, - }, - []*common2.Attribute{}, - []*common2.Input{}, - []*common2.Output{}, - 0, - []*program.Program{}, - ) - - testTx3IndexBlock = &types.Block{ - Header: common2.Header{}, - Transactions: []interfaces.Transaction{ - tx4, - }, - } -} - -func TestTx3IndexInit(t *testing.T) { - log.NewDefault(test.NodeLogPath, 0, 0, 0) - - var err error - tx3IndexDB, err = LoadBlockDB(test.DataPath) - assert.NoError(t, err) - - testTx3Index = indexers.NewTx3Index(tx3IndexDB) - assert.Equal(t, indexers.Tx3IndexName, testTx3Index.Name()) - assert.Equal(t, indexers.Tx3IndexKey, testTx3Index.Key()) - assert.NoError(t, testTx3Index.Init()) - - _ = tx3IndexDB.Update(func(dbTx database.Tx) error { - err := testTx3Index.Create(dbTx) - assert.NoError(t, err) - return err - }) -} - -func TestTx3Index_ConnectBlock(t *testing.T) { - initIndexBlock() - _ = tx3IndexDB.Update(func(dbTx database.Tx) error { - // tx3 should not in DB - assert.Equal(t, false, indexers.DBFetchTx3IndexEntry(dbTx, &tx3Hash)) - - // connect the block - err := testTx3Index.ConnectBlock(dbTx, testTx3IndexBlock) - assert.NoError(t, err) - - // tx3 should be stored in DB - assert.Equal(t, true, indexers.DBFetchTx3IndexEntry(dbTx, &tx3Hash)) - - return err - }) -} - -func TestTx3Index_Disconnect(t *testing.T) { - initIndexBlock() - _ = tx3IndexDB.Update(func(dbTx database.Tx) error { - // tx3 should be stored in DB - assert.Equal(t, true, indexers.DBFetchTx3IndexEntry(dbTx, &tx3Hash)) - - // disconnect the block - err := testTx3Index.DisconnectBlock(dbTx, testTx3IndexBlock) - assert.NoError(t, err) - - // tx3 should be removed from DB - assert.Equal(t, false, indexers.DBFetchTx3IndexEntry(dbTx, &tx3Hash)) - - return nil - }) -} - -func TestTx3IndexEnd(t *testing.T) { - _ = tx3IndexDB.Update(func(dbTx database.Tx) error { - meta := dbTx.Metadata() - err := meta.DeleteBucket(indexers.Tx3IndexKey) - assert.NoError(t, err) - return nil - }) - tx3IndexDB.Close() -}