Skip to content

eth/tracers/logger: accessList.equal performs extraneous checks that are mathematical contradictions after a length equality check #24658

@odeke-em

Description

@odeke-em

If we look at this code

// Cross reference the accounts first
if len(al) != len(other) {
return false
}
for addr := range al {
if _, ok := other[addr]; !ok {
return false
}
}
for addr := range other {
if _, ok := al[addr]; !ok {
return false
}
}

Bug or unnecessary code

There are extraneous checks
IMG_0555

Reasoning

Firstly we notice:

  1. We have affirmed that len(al) == len(other)
  2. al and other are Go maps for which a strong hashing algorithm wyhash; and have unique elements in them hence are technically by composition a "set" mathematically

Mathematically if set A and set B have the same number of elements and each element were unique; checking membership of all elements of A in B is reflexive as checking elements of B in A. If an extra element existed in A that wasn't in B and vice versa, then by definition that would be a contradiction of a set and failed precondition of len(A) == len(B), even if A and B weren't sets

Suggestion

We can remove the 2 extraneous checks that I highlighted and only check once so

func (al accessList) equal(other accessList) bool {
	// Cross reference the accounts first
	if len(al) != len(other) {
		return false
	}
	for addr := range al {
		if _, ok := other[addr]; !ok {
			return false
		}
	}

	// Accounts match, cross reference the storage slots too
	for addr, slots := range al {
		otherslots := other[addr]

		if len(slots) != len(otherslots) {
			return false
		}
		for hash := range slots {
			if _, ok := otherslots[hash]; !ok {
				return false
			}
		}
	}
	return true
}

and that should shave off unnecessary CPU cycle and RAM burn.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions