diff --git a/core/store/ChainStore/ChainStore.go b/core/store/ChainStore/ChainStore.go index 0f81790c..10c6cb2e 100644 --- a/core/store/ChainStore/ChainStore.go +++ b/core/store/ChainStore/ChainStore.go @@ -773,7 +773,8 @@ func (bd *ChainStore) persist(b *Block) error { b.Transactions[i].TxType == tx.BookKeeper || b.Transactions[i].TxType == tx.PrivacyPayload || b.Transactions[i].TxType == tx.BookKeeping || - b.Transactions[i].TxType == tx.DataFile { + b.Transactions[i].TxType == tx.DataFile || + b.Transactions[i].TxType == tx.DestroyUTXO { err = bd.SaveTransaction(b.Transactions[i], b.Blockdata.Height) if err != nil { return err @@ -798,6 +799,16 @@ func (bd *ChainStore) persist(b *Block) error { } } + if b.Transactions[i].TxType == tx.DestroyUTXO { + results, err := b.Transactions[i].GetMergedAssetIDValueFromReference() + if err != nil { + log.Error("[GetMergedAssetIDValueFromReference] failed.") + } + for assetId, value := range results { + quantities[assetId] -= value + } + } + for index := 0; index < len(b.Transactions[i].Outputs); index++ { output := b.Transactions[i].Outputs[index] programHash := output.ProgramHash diff --git a/core/transaction/TransactionBuilder.go b/core/transaction/TransactionBuilder.go index 63fb2829..2be7a1f2 100644 --- a/core/transaction/TransactionBuilder.go +++ b/core/transaction/TransactionBuilder.go @@ -142,3 +142,19 @@ func NewDataFileTransaction(path string, fileName string, note string, issuer *c Programs: []*program.Program{}, }, nil } + +func NewDestroyUTXOTransaction(inputs []*UTXOTxInput) (*Transaction, error) { + + //TODO: check arguments + + destroyUTXO := &payload.DestroyUTXO{} + + return &Transaction{ + TxType: DestroyUTXO, + Payload: destroyUTXO, + Attributes: []*TxAttribute{}, + UTXOInputs: inputs, + BalanceInputs: []*BalanceTxInput{}, + Programs: []*program.Program{}, + }, nil +} diff --git a/core/transaction/payload/DestroyUTXO.go b/core/transaction/payload/DestroyUTXO.go new file mode 100644 index 00000000..bef62ab5 --- /dev/null +++ b/core/transaction/payload/DestroyUTXO.go @@ -0,0 +1,20 @@ +package payload + +import "io" + +type DestroyUTXO struct { +} + +func (a *DestroyUTXO) Data(version byte) []byte { + //TODO: implement TransferAsset.Data() + return []byte{0} + +} + +func (a *DestroyUTXO) Serialize(w io.Writer, version byte) error { + return nil +} + +func (a *DestroyUTXO) Deserialize(r io.Reader, version byte) error { + return nil +} diff --git a/core/transaction/transaction.go b/core/transaction/transaction.go index 488fc84d..241c3b8c 100644 --- a/core/transaction/transaction.go +++ b/core/transaction/transaction.go @@ -30,6 +30,7 @@ const ( Record TransactionType = 0x81 DeployCode TransactionType = 0xd0 DataFile TransactionType = 0x12 + DestroyUTXO TransactionType = 0x18 ) //Payload define the func for loading the payload data @@ -200,6 +201,8 @@ func (tx *Transaction) DeserializeUnsignedWithoutType(r io.Reader) error { tx.Payload = new(payload.PrivacyPayload) case DataFile: tx.Payload = new(payload.DataFile) + case DestroyUTXO: + tx.Payload = new(payload.DestroyUTXO) default: return errors.New("[Transaction],invalide transaction type.") } @@ -293,9 +296,6 @@ func (tx *Transaction) GetProgramHashes() ([]Uint160, error) { hashs = append(hashs, astHash) case IssueAsset: result := tx.GetMergedAssetIDValueFromOutputs() - if err != nil { - return nil, NewDetailErr(err, ErrNoCode, "[Transaction], GetTransactionResults failed.") - } for k := range result { tx, err := TxStore.GetTransaction(k) if err != nil { @@ -339,6 +339,27 @@ func (tx *Transaction) GetProgramHashes() ([]Uint160, error) { return nil, NewDetailErr(err, ErrNoCode, "[Transaction], GetProgramHashes ToCodeHash failed.") } hashs = append(hashs, astHash) + case DestroyUTXO: + inputs, err := tx.GetMergedAssetIDValueFromReference() + if err != nil { + return nil, NewDetailErr(err, ErrNoCode, "[Transaction], GetTransactionInputs failed.") + } + for k := range inputs { + tx, err := TxStore.GetTransaction(k) + if err != nil { + return nil, NewDetailErr(err, ErrNoCode, fmt.Sprintf("[Transaction], GetTransaction failed With AssetID:=%x", k)) + } + if tx.TxType != RegisterAsset { + return nil, NewDetailErr(errors.New("[Transaction] error"), ErrNoCode, fmt.Sprintf("[Transaction], Transaction Type ileage With AssetID:=%x", k)) + } + + switch v1 := tx.Payload.(type) { + case *payload.RegisterAsset: + hashs = append(hashs, v1.Controller) + default: + return nil, NewDetailErr(errors.New("[Transaction] error"), ErrNoCode, fmt.Sprintf("[Transaction], payload is illegal", k)) + } + } default: } //remove dupilicated hashes diff --git a/core/validation/txValidator.go b/core/validation/txValidator.go index 02e8a4b0..3a532ef6 100644 --- a/core/validation/txValidator.go +++ b/core/validation/txValidator.go @@ -31,11 +31,11 @@ func VerifyTransaction(Tx *tx.Transaction) error { return err } - if err := CheckTransactionContracts(Tx); err != nil { + if err := CheckTransactionPayload(Tx); err != nil { return err } - if err := CheckTransactionPayload(Tx); err != nil { + if err := CheckTransactionContracts(Tx); err != nil { return err } @@ -192,10 +192,7 @@ func CheckTransactionBalance(Tx *tx.Transaction) error { return errors.New("Invalide transaction UTXO output.") } } - if Tx.TxType == tx.IssueAsset { - if len(Tx.UTXOInputs) > 0 { - return errors.New("Invalide Issue transaction.") - } + if Tx.TxType == tx.IssueAsset || Tx.TxType == tx.DestroyUTXO { return nil } results, err := Tx.GetTransactionResults() @@ -238,20 +235,27 @@ func CheckTransactionPayload(Tx *tx.Transaction) error { return nil case *payload.RegisterAsset: if pld.Asset.Precision < asset.MinPrecision || pld.Asset.Precision > asset.MaxPrecision { - return errors.New("Invalide asset Precision.") + return errors.New("[CheckTransactionPayload],invalid asset Precision.") } if checkAmountPrecise(pld.Amount, pld.Asset.Precision) { - return errors.New("Invalide asset value,out of precise.") + return errors.New("[CheckTransactionPayload],invalid asset value,out of precise.") } case *payload.IssueAsset: + if len(Tx.UTXOInputs) > 0 { + return errors.New("Invalide Issue transaction.") + } case *payload.TransferAsset: case *payload.BookKeeping: case *payload.PrivacyPayload: case *payload.Record: case *payload.DeployCode: case *payload.DataFile: + case *payload.DestroyUTXO: + if len(Tx.Outputs) > 0 { + return errors.New("[CheckTransactionPayload],invalid transaction outputs.") + } default: - return errors.New("[txValidator],invalidate transaction payload type.") + return errors.New("[CheckTransactionPayload],invalid transaction payload type.") } return nil } diff --git a/net/httpjsonrpc/TransPayloadToHex.go b/net/httpjsonrpc/TransPayloadToHex.go index c03bbe21..35909cee 100644 --- a/net/httpjsonrpc/TransPayloadToHex.go +++ b/net/httpjsonrpc/TransPayloadToHex.go @@ -137,6 +137,7 @@ func TransPayloadToHex(p Payload) PayloadInfo { obj.Issuer.X = object.Issuer.X.String() obj.Issuer.Y = object.Issuer.Y.String() return obj + case *payload.DestroyUTXO: } return nil }