Browse Source

split into smaller functions

pull/8094/head
William Banfield 3 years ago
parent
commit
438adcd0dd
No known key found for this signature in database GPG Key ID: EFAD3442BF29E3AC
1 changed files with 65 additions and 54 deletions
  1. +65
    -54
      types/tx.go

+ 65
- 54
types/tx.go View File

@ -182,10 +182,13 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error {
// and once by sorting the set of the added, removed, and unmodified transactions indexes,
// which, when combined, comprise the complete list of transactions.
//
// The original list is iterated once and the modified list and set of indexes are
// also iterated once each.
// Asymptotically, this yields a total runtime of O(N*log(N) + N + 2*M*log(M) + 2*M),
// The original list is iterated once and the modified list is iterated multiple times,
// one time alongside each of the 3 indexes for a total of 4 iterations of the modified list.
// Asymptotically, this yields a total runtime of O(N*log(N) + N + 2*M*log(M) + 4*M),
// in the input size of the original list and the input size of the new list respectively.
// A 2 * M performance gain is possible but iterating all of the indexes simultaneously
// alongside the original list, but the multiple iterations were preferred to be more
// readable and maintainable.
// Sort a copy of the complete transaction slice so we can check for
// duplication. The copy is so we do not change the original ordering.
@ -227,73 +230,81 @@ func (t TxRecordSet) Validate(maxSizeBytes int64, otxs Txs) error {
copy(otxsCopy, otxs)
sort.Sort(Txs(otxsCopy))
unmodifiedIdx, addedIdx, removedIdx := 0, 0, 0
for i := 0; i < len(otxsCopy); i++ {
if addedIdx == len(addedCopy) &&
removedIdx == len(removedCopy) &&
unmodifiedIdx == len(unmodifiedCopy) {
// we've reached the end of all of the sorted indexes without
// detecting any issues.
break
}
if ix, ok := containsAllTxs(otxsCopy, unmodifiedCopy); !ok {
return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", unmodifiedCopy[ix].Hash())
}
if ix, ok := containsAllTxs(otxsCopy, removedCopy); !ok {
return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[ix].Hash())
}
if ix, ok := containsNoneTxs(otxsCopy, addedCopy); !ok {
return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", addedCopy[ix].Hash())
}
return nil
}
// containsNoneTxs checks that list a contains none of the transactions in list
// b. If a match is found, the index in b of the matching transaction is returned.
// Both lists must be sorted.
func containsNoneTxs(a, b []Tx) (int, bool) {
aix, bix := 0, 0
for ; aix < len(a); aix++ {
LOOP:
// iterate over the sorted addedIndex until we reach a value that sorts
// higher than the value we are examining in the original list.
for addedIdx < len(addedCopy) {
switch bytes.Compare(addedCopy[addedIdx], otxsCopy[i]) {
for bix < len(b) {
switch bytes.Compare(b[bix], a[aix]) {
case 0:
return fmt.Errorf("existing transaction incorrectly marked as added, transaction hash: %x", otxsCopy[i].Hash())
return bix, false
case -1:
addedIdx++
bix++
// we've reached the end of b, and the last value in b was
// smaller than the value under the iterator of a.
// a's values never get smaller, so we know there are no more matches
// in the list. We can terminate the iteration here.
if bix == len(b) {
return -1, true
}
case 1:
break LOOP
}
}
}
return -1, true
}
// The following iterator checks work in the same way on the removed iterator
// and the unmodified iterator. They check that all the values in the respective sorted
// index are present in the original list.
//
// For the removed check, we compare the value under the removed iterator to the value
// under the iterator for the total sorted list. If they match, we advance the
// removed iterator one position. If they don't match, then the value under
// the remove iterator should be greater.
// If it is not, then there is a value in the the removed list that was not present in the
// original list.
//
// The same logic applies for the unmodified check.
if removedIdx < len(removedCopy) {
switch bytes.Compare(removedCopy[removedIdx], otxsCopy[i]) {
case 0:
removedIdx++
case -1:
return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[i].Hash())
}
// containsAllTxs checks that super contains all of the transactions in the sub
// list. If not all values in sub are present in super, the index in sub of the
// first Tx absent from super is returned.
func containsAllTxs(super, sub []Tx) (int, bool) {
// The following iteration assumes sorted lists.
// The checks ensure that all the values in the sorted sub list are present in the sorted super list.
//
// We compare the value under the sub iterator to the value
// under the super iterator. If they match, we advance the
// sub iterator one position. If they don't match, then the value under
// the sub iterator should be greater.
// If it is not, then there is a value in the the sub list that is not present in the
// super list.
subIx := 0
for _, cur := range super {
if subIx == len(sub) {
return -1, true
}
if unmodifiedIdx < len(unmodifiedCopy) {
switch bytes.Compare(unmodifiedCopy[unmodifiedIdx], otxsCopy[i]) {
case 0:
unmodifiedIdx++
case -1:
return fmt.Errorf("new transaction incorrectly marked as unmodified, transaction hash: %x", removedCopy[i].Hash())
}
switch bytes.Compare(sub[subIx], cur) {
case 0:
subIx++
case -1:
return subIx, false
}
}
// Check that the loop visited all values of the removed and unmodified transactions.
// Check that the loop visited all values of the transactions from sub.
// If it did not, then there are values present in these indexes that were not
// present in the original list of transactions.
// present in the super list of transactions.
if removedIdx != len(removedCopy) {
return fmt.Errorf("new transaction incorrectly marked as removed, transaction hash: %x", removedCopy[removedIdx].Hash())
}
if unmodifiedIdx != len(unmodifiedCopy) {
return fmt.Errorf("new transaction incorrectly marked as unmodified, transaction hash: %x", unmodifiedCopy[unmodifiedIdx].Hash())
if subIx != len(sub) {
return subIx, false
}
return nil
return -1, true
}
// TxsToTxRecords converts from a list of Txs to a list of TxRecords. All of the


Loading…
Cancel
Save