core/transaction: use new transaction.InOut for References

We don't need a map here, use simpler structures.
This commit is contained in:
Roman Khimov 2020-02-26 10:58:20 +03:00
parent 80de208a68
commit 9f7018503a
5 changed files with 46 additions and 41 deletions

View file

@ -1009,28 +1009,28 @@ func (bc *Blockchain) GetConfig() config.ProtocolConfiguration {
return bc.config return bc.config
} }
// References returns a map with input coin reference (prevhash and index) as key // References maps transaction's inputs into a slice of InOuts, effectively
// and transaction output as value from a transaction t. // joining each Input with the corresponding Output.
// @TODO: unfortunately we couldn't attach this method to the Transaction struct in the // @TODO: unfortunately we couldn't attach this method to the Transaction struct in the
// transaction package because of a import cycle problem. Perhaps we should think to re-design // transaction package because of a import cycle problem. Perhaps we should think to re-design
// the code base to avoid this situation. // the code base to avoid this situation.
func (bc *Blockchain) References(t *transaction.Transaction) map[transaction.Input]*transaction.Output { func (bc *Blockchain) References(t *transaction.Transaction) ([]transaction.InOut, error) {
references := make(map[transaction.Input]*transaction.Output) references := make([]transaction.InOut, 0, len(t.Inputs))
for _, inputs := range transaction.GroupInputsByPrevHash(t.Inputs) { for _, inputs := range transaction.GroupInputsByPrevHash(t.Inputs) {
prevHash := inputs[0].PrevHash prevHash := inputs[0].PrevHash
tx, _, err := bc.dao.GetTransaction(prevHash) tx, _, err := bc.dao.GetTransaction(prevHash)
if err != nil { if err != nil {
return nil return nil, errors.New("bad input reference")
} }
for _, in := range inputs { for _, in := range inputs {
if int(in.PrevIndex) > len(tx.Outputs)-1 { if int(in.PrevIndex) > len(tx.Outputs)-1 {
return nil return nil, errors.New("bad input reference")
} }
references[*in] = &tx.Outputs[in.PrevIndex] references = append(references, transaction.InOut{In: *in, Out: tx.Outputs[in.PrevIndex]})
} }
} }
return references return references, nil
} }
// FeePerByte returns network fee divided by the size of the transaction. // FeePerByte returns network fee divided by the size of the transaction.
@ -1041,9 +1041,13 @@ func (bc *Blockchain) FeePerByte(t *transaction.Transaction) util.Fixed8 {
// NetworkFee returns network fee. // NetworkFee returns network fee.
func (bc *Blockchain) NetworkFee(t *transaction.Transaction) util.Fixed8 { func (bc *Blockchain) NetworkFee(t *transaction.Transaction) util.Fixed8 {
inputAmount := util.Fixed8FromInt64(0) inputAmount := util.Fixed8FromInt64(0)
for _, txOutput := range bc.References(t) { refs, err := bc.References(t)
if txOutput.AssetID == UtilityTokenID() { if err != nil {
inputAmount.Add(txOutput.Amount) return inputAmount
}
for i := range refs {
if refs[i].Out.AssetID == UtilityTokenID() {
inputAmount.Add(refs[i].Out.Amount)
} }
} }
@ -1310,14 +1314,14 @@ func (bc *Blockchain) GetTransactionResults(t *transaction.Transaction) []*trans
var results []*transaction.Result var results []*transaction.Result
tempGroupResult := make(map[util.Uint256]util.Fixed8) tempGroupResult := make(map[util.Uint256]util.Fixed8)
references := bc.References(t) references, err := bc.References(t)
if references == nil { if err != nil {
return nil return nil
} }
for _, output := range references { for _, inout := range references {
tempResults = append(tempResults, &transaction.Result{ tempResults = append(tempResults, &transaction.Result{
AssetID: output.AssetID, AssetID: inout.Out.AssetID,
Amount: output.Amount, Amount: inout.Out.Amount,
}) })
} }
for _, output := range t.Outputs { for _, output := range t.Outputs {
@ -1534,16 +1538,13 @@ func (bc *Blockchain) GetScriptHashesForVerifying(t *transaction.Transaction) ([
if t.Type == transaction.ClaimType { if t.Type == transaction.ClaimType {
return bc.GetScriptHashesForVerifyingClaim(t) return bc.GetScriptHashesForVerifyingClaim(t)
} }
references := bc.References(t) references, err := bc.References(t)
if references == nil { if err != nil {
return nil, errors.New("invalid inputs") return nil, err
} }
hashes := make(map[util.Uint160]bool) hashes := make(map[util.Uint160]bool)
for _, i := range t.Inputs { for i := range references {
h := references[i].ScriptHash hashes[references[i].Out.ScriptHash] = true
if _, ok := hashes[h]; !ok {
hashes[h] = true
}
} }
for _, a := range t.Attributes { for _, a := range t.Attributes {
if a.Usage == transaction.Script { if a.Usage == transaction.Script {

View file

@ -39,7 +39,7 @@ type Blockchainer interface {
GetTestVM() (*vm.VM, storage.Store) GetTestVM() (*vm.VM, storage.Store)
GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error) GetTransaction(util.Uint256) (*transaction.Transaction, uint32, error)
GetUnspentCoinState(util.Uint256) *UnspentCoinState GetUnspentCoinState(util.Uint256) *UnspentCoinState
References(t *transaction.Transaction) map[transaction.Input]*transaction.Output References(t *transaction.Transaction) ([]transaction.InOut, error)
mempool.Feer // fee interface mempool.Feer // fee interface
PoolTx(*transaction.Transaction) error PoolTx(*transaction.Transaction) error
VerifyTx(*transaction.Transaction, *block.Block) error VerifyTx(*transaction.Transaction, *block.Block) error

View file

@ -34,12 +34,6 @@ const (
DefaultAssetLifetime = 1 + BlocksPerYear DefaultAssetLifetime = 1 + BlocksPerYear
) )
// txInOut is used to pushed one key-value pair from References() onto the stack.
type txInOut struct {
in transaction.Input
out transaction.Output
}
// headerGetVersion returns version from the header. // headerGetVersion returns version from the header.
func (ic *interopContext) headerGetVersion(v *vm.VM) error { func (ic *interopContext) headerGetVersion(v *vm.VM) error {
header, err := popHeaderFromVM(v) header, err := popHeaderFromVM(v)
@ -141,14 +135,16 @@ func (ic *interopContext) txGetReferences(v *vm.VM) error {
if !ok { if !ok {
return fmt.Errorf("type mismatch: %T is not a Transaction", txInterface) return fmt.Errorf("type mismatch: %T is not a Transaction", txInterface)
} }
refs := ic.bc.References(tx) refs, err := ic.bc.References(tx)
if err != nil {
return err
}
if len(refs) > vm.MaxArraySize { if len(refs) > vm.MaxArraySize {
return errors.New("too many references") return errors.New("too many references")
} }
stackrefs := make([]vm.StackItem, 0, len(refs)) stackrefs := make([]vm.StackItem, 0, len(refs))
for _, k := range tx.Inputs { for _, tio := range refs {
tio := txInOut{k, *refs[k]}
stackrefs = append(stackrefs, vm.NewInteropItem(tio)) stackrefs = append(stackrefs, vm.NewInteropItem(tio))
} }
v.Estack().PushVal(stackrefs) v.Estack().PushVal(stackrefs)
@ -243,11 +239,11 @@ func popInputFromVM(v *vm.VM) (*transaction.Input, error) {
inInterface := v.Estack().Pop().Value() inInterface := v.Estack().Pop().Value()
input, ok := inInterface.(*transaction.Input) input, ok := inInterface.(*transaction.Input)
if !ok { if !ok {
txio, ok := inInterface.(txInOut) txio, ok := inInterface.(transaction.InOut)
if !ok { if !ok {
return nil, fmt.Errorf("type mismatch: %T is not an Input or txInOut", inInterface) return nil, fmt.Errorf("type mismatch: %T is not an Input or InOut", inInterface)
} }
input = &txio.in input = &txio.In
} }
return input, nil return input, nil
} }
@ -277,11 +273,11 @@ func popOutputFromVM(v *vm.VM) (*transaction.Output, error) {
outInterface := v.Estack().Pop().Value() outInterface := v.Estack().Pop().Value()
output, ok := outInterface.(*transaction.Output) output, ok := outInterface.(*transaction.Output)
if !ok { if !ok {
txio, ok := outInterface.(txInOut) txio, ok := outInterface.(transaction.InOut)
if !ok { if !ok {
return nil, fmt.Errorf("type mismatch: %T is not an Output or txInOut", outInterface) return nil, fmt.Errorf("type mismatch: %T is not an Output or InOut", outInterface)
} }
output = &txio.out output = &txio.Out
} }
return output, nil return output, nil
} }

View file

@ -0,0 +1,8 @@
package transaction
// InOut represents an Input bound to its corresponding Output which is a useful
// combination for many purposes.
type InOut struct {
In Input
Out Output
}

View file

@ -33,7 +33,7 @@ func (chain testChain) GetConfig() config.ProtocolConfiguration {
panic("TODO") panic("TODO")
} }
func (chain testChain) References(t *transaction.Transaction) map[transaction.Input]*transaction.Output { func (chain testChain) References(t *transaction.Transaction) ([]transaction.InOut, error) {
panic("TODO") panic("TODO")
} }