diff --git a/common/changeset/storage_changeset.go b/common/changeset/storage_changeset.go index 512af2ef6..a21eeae9c 100644 --- a/common/changeset/storage_changeset.go +++ b/common/changeset/storage_changeset.go @@ -11,8 +11,9 @@ import ( ) const ( + DefaultIncarnation = uint64(1) storageEnodingIndexSize = 4 - storageEnodingStartElem = uint32(4) + storageEnodingStartElem = 4 storageEnodingLengthOfNumOfElements = 4 storageEnodingLengthOfDict = 2 storageEnodingLengthOfNumTypeOfElements = 2 @@ -40,6 +41,7 @@ numOfUint32Values uint16 [len(val0), len(val0)+len(val1), ..., len(val0)+len(val1)+...+len(val_{numOfUint8Values-1})] []uint8 [len(valnumOfUint8Values), len(val0)+len(val1), ..., len(val0)+len(val1)+...+len(val_{numOfUint16Values-1})] []uint16 [len(valnumOfUint16Values), len(val0)+len(val1), ..., len(val0)+len(val1)+...+len(val_{numOfUint32Values-1})] []uint32 +[elementNum:incarnation] - optional [uint32:uint64...] */ func EncodeStorage(s *ChangeSet) ([]byte, error) { @@ -54,30 +56,32 @@ func EncodeStorage(s *ChangeSet) ([]byte, error) { return nil, err } - addrHashesMap := make(map[common.Hash]uint32) - addrHashList := make([]byte, 0) + addrHashesMap := make([]uint32, n) + var addrHashList []byte + notDefaultIncarnationList := make([]byte, 0) //collect information about unique addHashes and non default incarnations - nextIDAddrHash := uint32(0) - var addrHash common.Hash - for i := 0; i < n; i++ { - //copy addrHash - copy( - addrHash[:], - s.Changes[i].Key[0:common.HashLength], - ) - - //fill addrHashesMap and addrHashList - if _, ok := addrHashesMap[addrHash]; !ok { - addrHashesMap[addrHash] = nextIDAddrHash - nextIDAddrHash++ - addrHashList = append(addrHashList, addrHash[:]...) + var addrID uint32 + var addrIdxToIncarnation [12]byte + for i, change := range s.Changes { + if i == 0 || !bytes.Equal(change.Key[:common.HashLength], s.Changes[i-1].Key[:common.HashLength]) { + if i > 0 { + addrID++ + } + addrHashList = append(addrHashList, change.Key[:common.HashLength]...) + incarnation := ^binary.BigEndian.Uint64(change.Key[common.HashLength : common.HashLength+common.IncarnationLength]) + if incarnation != DefaultIncarnation { + binary.BigEndian.PutUint32(addrIdxToIncarnation[:4], addrID) + binary.BigEndian.PutUint64(addrIdxToIncarnation[4:12], ^incarnation) + notDefaultIncarnationList = append(notDefaultIncarnationList, addrIdxToIncarnation[:]...) + } } + addrHashesMap[i] = addrID } //write numOfUniqAddrHashes numOfUniqAddrHashes := make([]byte, storageEnodingLengthOfDict) - binary.BigEndian.PutUint16(numOfUniqAddrHashes, uint16(len(addrHashesMap))) + binary.BigEndian.PutUint16(numOfUniqAddrHashes, uint16(addrID+1)) if _, err := buf.Write(numOfUniqAddrHashes); err != nil { return nil, err } @@ -87,60 +91,62 @@ func EncodeStorage(s *ChangeSet) ([]byte, error) { return nil, err } - lenOfAddr := getNumOfBytesByLen(len(addrHashesMap)) - values := new(bytes.Buffer) - lengthes := make([]byte, storageEnodingLengthOfNumTypeOfElements*3) + lenOfAddr := getNumOfBytesByLen(int(addrID + 1)) numOfUint8 := uint16(0) numOfUint16 := uint16(0) numOfUint32 := uint16(0) - keys := new(bytes.Buffer) lengthOfValues := uint32(0) row := make([]byte, lenOfAddr+common.HashLength) - for i := 0; i < len(s.Changes); i++ { + for i, change := range s.Changes { writeKeyRow( - addrHashesMap[common.BytesToHash(s.Changes[i].Key[0:common.HashLength])], + addrHashesMap[i], row[0:lenOfAddr], ) - copy(row[lenOfAddr:lenOfAddr+common.HashLength], common.CopyBytes(s.Changes[i].Key[common.IncarnationLength+common.HashLength:common.IncarnationLength+2*common.HashLength])) - keys.Write(row) - - lengthOfValues += uint32(len(s.Changes[i].Value)) + copy(row[lenOfAddr:lenOfAddr+common.HashLength], change.Key[common.IncarnationLength+common.HashLength:common.IncarnationLength+2*common.HashLength]) + buf.Write(row) + } + // Remember position to fix up the lengths later + lengthPos := buf.Len() + uint16b := make([]byte, 2) + // Reserve 3 positions for lengths + buf.Write(uint16b) + buf.Write(uint16b) + buf.Write(uint16b) + uint32b := make([]byte, 4) + for _, change := range s.Changes { + lengthOfValues += uint32(len(change.Value)) switch { case lengthOfValues <= 255: numOfUint8++ - lengthes = append(lengthes, uint8(lengthOfValues)) + buf.WriteByte(uint8(lengthOfValues)) case lengthOfValues <= 65535: numOfUint16++ - uint16b := make([]byte, 2) binary.BigEndian.PutUint16(uint16b, uint16(lengthOfValues)) - lengthes = append(lengthes, uint16b...) + buf.Write(uint16b) default: numOfUint32++ - uint32b := make([]byte, 4) binary.BigEndian.PutUint32(uint32b, lengthOfValues) - lengthes = append(lengthes, uint32b...) + buf.Write(uint32b) } - values.Write(s.Changes[i].Value) } - binary.BigEndian.PutUint16(lengthes[0:storageEnodingLengthOfNumTypeOfElements], numOfUint8) - binary.BigEndian.PutUint16(lengthes[storageEnodingLengthOfNumTypeOfElements:2*storageEnodingLengthOfNumTypeOfElements], numOfUint16) - binary.BigEndian.PutUint16(lengthes[2*storageEnodingLengthOfNumTypeOfElements:3*storageEnodingLengthOfNumTypeOfElements], numOfUint32) - if _, err := buf.Write(keys.Bytes()); err != nil { - return nil, err + for _, change := range s.Changes { + buf.Write(change.Value) } - if _, err := buf.Write(lengthes); err != nil { - return nil, err + if len(notDefaultIncarnationList) > 0 { + if _, err := buf.Write(notDefaultIncarnationList); err != nil { + return nil, err + } } - if _, err := buf.Write(values.Bytes()); err != nil { - return nil, err - } - - byt := buf.Bytes() - return byt, nil + b := buf.Bytes() + // Fix up the lengths + binary.BigEndian.PutUint16(b[lengthPos:], numOfUint8) + binary.BigEndian.PutUint16(b[lengthPos+2:], numOfUint16) + binary.BigEndian.PutUint16(b[lengthPos+4:], numOfUint32) + return b, nil } func DecodeStorage(b []byte) (*ChangeSet, error) { @@ -153,50 +159,65 @@ func DecodeStorage(b []byte) (*ChangeSet, error) { return h, fmt.Errorf("decode: input too short (%d bytes)", len(b)) } - //numOfElements uint32 - numOfElements := binary.BigEndian.Uint32(b[0:storageEnodingLengthOfNumOfElements]) + numOfElements := int(binary.BigEndian.Uint32(b[0:storageEnodingLengthOfNumOfElements])) h.Changes = make([]Change, numOfElements) if numOfElements == 0 { return h, nil } - dictLen := binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements : storageEnodingLengthOfNumOfElements+storageEnodingLengthOfDict]) - addMap := make(map[uint32]common.Hash) - for i := 0; i < int(dictLen); i++ { + dictLen := int(binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements : storageEnodingLengthOfNumOfElements+storageEnodingLengthOfDict])) + addMap := make(map[uint32][]byte) + for i := 0; i < dictLen; i++ { elemStart := storageEnodingLengthOfNumOfElements + storageEnodingLengthOfDict + i*common.HashLength - addMap[uint32(i)] = common.BytesToHash(b[elemStart : elemStart+common.HashLength]) + addMap[uint32(i)] = b[elemStart : elemStart+common.HashLength] } lenOfValsPos := storageEnodingStartElem + - 2 + uint32(dictLen)*common.HashLength + - numOfElements*uint32(getNumOfBytesByLen(int(dictLen))+common.HashLength) + 2 + dictLen*common.HashLength + + numOfElements*(getNumOfBytesByLen(dictLen)+common.HashLength) numOfUint8 := int(binary.BigEndian.Uint16(b[lenOfValsPos : lenOfValsPos+2])) numOfUint16 := int(binary.BigEndian.Uint16(b[lenOfValsPos+2 : lenOfValsPos+4])) numOfUint32 := int(binary.BigEndian.Uint16(b[lenOfValsPos+4 : lenOfValsPos+6])) lenOfValsPos = lenOfValsPos + 3*storageEnodingLengthOfNumTypeOfElements - valuesPos := lenOfValsPos + uint32(numOfUint8) + uint32(numOfUint16*2) + uint32(numOfUint32*4) + valuesPos := lenOfValsPos + numOfUint8 + numOfUint16*2 + numOfUint32*4 - elementStart := storageEnodingStartElem + storageEnodingLengthOfDict + uint32(dictLen)*common.HashLength - key := make([]byte, common.HashLength*2+common.IncarnationLength) + incarnationPosition := lenOfValsPos + calculateIncarnationPos3(b[lenOfValsPos:], numOfUint8, numOfUint16, numOfUint32) + notDefaultIncarnation := make(map[uint32]uint64) - lenOfAddHash := uint32(getNumOfBytesByLen(len(addMap))) - //lastValLen:=0 - for i := uint32(0); i < numOfElements; i++ { + if len(b) > incarnationPosition { + if len(b[incarnationPosition:])%12 != 0 { + return h, fmt.Errorf("decode: incarnatin part is incorrect(%d bytes)", len(b[incarnationPosition:])) + } + for i := incarnationPosition; i < len(b); i += 12 { + id := binary.BigEndian.Uint32(b[i : i+4]) + inc := ^binary.BigEndian.Uint64(b[i+4 : i+12]) + notDefaultIncarnation[id] = inc + } + } + + elementStart := storageEnodingStartElem + storageEnodingLengthOfDict + dictLen*common.HashLength + + lenOfAddHash := getNumOfBytesByLen(len(addMap)) + for i := 0; i < numOfElements; i++ { //copy addrHash + key := make([]byte, common.HashLength*2+common.IncarnationLength) elem := elementStart + i*(lenOfAddHash+common.HashLength) - copy( - key[0:common.HashLength], - readFromMap(addMap, b[elem:elem+lenOfAddHash]).Bytes(), - ) + addrIdx := getUint32(b[elem : elem+lenOfAddHash]) + copy(key[:common.HashLength], addMap[addrIdx]) + if inc, ok := notDefaultIncarnation[addrIdx]; ok { + binary.BigEndian.PutUint64(key[common.HashLength:], ^inc) + } else { + binary.BigEndian.PutUint64(key[common.HashLength:], ^DefaultIncarnation) + } //copy key hash copy( key[common.HashLength+common.IncarnationLength:2*common.HashLength+common.IncarnationLength], common.CopyBytes(b[elem+lenOfAddHash:elem+lenOfAddHash+common.HashLength]), ) - binary.BigEndian.PutUint64(key[common.HashLength:common.HashLength+common.IncarnationLength], ^uint64(1)) - h.Changes[i].Key = common.CopyBytes(key) + + h.Changes[i].Key = key h.Changes[i].Value = findVal(b[lenOfValsPos:valuesPos], b[valuesPos:], i, numOfUint8, numOfUint16, numOfUint32) } return h, nil @@ -216,41 +237,57 @@ func getNumOfBytesByLen(n int) int { } } -func findVal(lenOfVals []byte, values []byte, i uint32, numOfUint8, numOfUint16, numOfUint32 int) []byte { - lenOfValStart := uint32(0) - lenOfValEnd := uint32(0) +func calculateIncarnationPos3(b []byte, numOfUint8, numOfUint16, numOfUint32 int) int { + res := 0 + end := 0 switch { - case i < uint32(numOfUint8): - lenOfValEnd = uint32(lenOfVals[i]) + case numOfUint32 > 0: + end = numOfUint8 + numOfUint16*2 + numOfUint32*4 + res = int(binary.BigEndian.Uint32(b[end-4:end])) + end + case numOfUint16 > 0: + end = numOfUint8 + numOfUint16*2 + res = int(binary.BigEndian.Uint16(b[end-2:end])) + end + case numOfUint8 > 0: + end = numOfUint8 + res = int(b[end-1]) + end + default: + return 0 + } + return res +} + +func findVal(lenOfVals []byte, values []byte, i int, numOfUint8, numOfUint16, numOfUint32 int) []byte { + lenOfValStart := 0 + lenOfValEnd := 0 + switch { + case i < numOfUint8: + lenOfValEnd = int(lenOfVals[i]) if i > 0 { - lenOfValStart = uint32(lenOfVals[i-1]) + lenOfValStart = int(lenOfVals[i-1]) } - return common.CopyBytes(values[lenOfValStart:lenOfValEnd]) - case i < uint32(numOfUint8)+uint32(numOfUint16): - one := uint32(numOfUint8) + (i-uint32(numOfUint8))*2 - lenOfValEnd = uint32(binary.BigEndian.Uint16(lenOfVals[one : one+2])) - if i-1 < uint32(numOfUint8) { - lenOfValStart = uint32(lenOfVals[i-1]) + case i < numOfUint8+numOfUint16: + one := (i-numOfUint8)*2 + numOfUint8 + lenOfValEnd = int(binary.BigEndian.Uint16(lenOfVals[one : one+2])) + if i-1 < numOfUint8 { + lenOfValStart = int(lenOfVals[i-1]) } else { - one = uint32(numOfUint8) + (i-1-uint32(numOfUint8))*2 - lenOfValStart = uint32(binary.BigEndian.Uint16(lenOfVals[one : one+2])) + one = (i-1)*2 - numOfUint8 + lenOfValStart = int(binary.BigEndian.Uint16(lenOfVals[one : one+2])) } - return common.CopyBytes(values[lenOfValStart:lenOfValEnd]) - case i < uint32(numOfUint8)+uint32(numOfUint16)+uint32(numOfUint32): - fmt.Println(i, uint32(numOfUint8), numOfUint16, numOfUint32) - one := uint32(numOfUint8) + uint32(numOfUint16)*2 + (i-uint32(numOfUint8)-uint32(numOfUint16))*4 - lenOfValEnd = binary.BigEndian.Uint32(lenOfVals[one : one+4]) - if i-1 < uint32(numOfUint8)+uint32(numOfUint16) { - one = uint32(numOfUint8) + (i-1-uint32(numOfUint8))*2 - lenOfValStart = uint32(binary.BigEndian.Uint16(lenOfVals[one : one+2])) + case i < numOfUint8+numOfUint16+numOfUint32: + one := numOfUint8 + numOfUint16*2 + (i-numOfUint8-numOfUint16)*4 + lenOfValEnd = int(binary.BigEndian.Uint32(lenOfVals[one : one+4])) + if i-1 < numOfUint8+numOfUint16 { + one = (i-1)*2 - numOfUint8 + lenOfValStart = int(binary.BigEndian.Uint16(lenOfVals[one : one+2])) } else { - one := uint32(numOfUint8) + uint32(numOfUint16)*2 + (i-1-uint32(numOfUint8)-uint32(numOfUint16))*4 - lenOfValStart = binary.BigEndian.Uint32(lenOfVals[one : one+4]) + one = numOfUint8 + numOfUint16*2 + (i-1-numOfUint8-numOfUint16)*4 + lenOfValStart = int(binary.BigEndian.Uint32(lenOfVals[one : one+4])) } - return common.CopyBytes(values[lenOfValStart:lenOfValEnd]) default: panic("findval err") } + return common.CopyBytes(values[lenOfValStart:lenOfValEnd]) } func writeKeyRow(id uint32, row []byte) { @@ -267,16 +304,17 @@ func writeKeyRow(id uint32, row []byte) { panic("wrong size of row") } } -func readFromMap(m map[uint32]common.Hash, row []byte) common.Hash { + +func getUint32(row []byte) uint32 { switch len(row) { case 1: - return m[uint32(row[0])] + return uint32(row[0]) case 2: - return m[uint32(binary.BigEndian.Uint16(row))] + return uint32(binary.BigEndian.Uint16(row)) case 4: - return m[binary.BigEndian.Uint32(row)] + return binary.BigEndian.Uint32(row) case 8: - return m[uint32(binary.BigEndian.Uint64(row))] + return uint32(binary.BigEndian.Uint64(row)) default: panic("wrong") } @@ -292,50 +330,65 @@ func (b StorageChangeSetBytes) Walk(f func(k, v []byte) error) error { return fmt.Errorf("decode: input too short (%d bytes)", len(b)) } - numOfItems := binary.BigEndian.Uint32(b[0:4]) + numOfItems := int(binary.BigEndian.Uint32(b[0:4])) if numOfItems == 0 { return nil } - numOfUniqueItems := binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements : storageEnodingLengthOfNumOfElements+storageEnodingLengthOfDict]) + numOfUniqueItems := int(binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements : storageEnodingLengthOfNumOfElements+storageEnodingLengthOfDict])) lenOfValsPos := storageEnodingStartElem + storageEnodingLengthOfDict + - uint32(numOfUniqueItems)*common.HashLength + - numOfItems*uint32(getNumOfBytesByLen(int(numOfUniqueItems))+common.HashLength) + numOfUniqueItems*common.HashLength + + numOfItems*(getNumOfBytesByLen(numOfUniqueItems)+common.HashLength) numOfUint8 := int(binary.BigEndian.Uint16(b[lenOfValsPos : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements])) numOfUint16 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*2])) numOfUint32 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*2 : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*3])) lenOfValsPos += storageEnodingLengthOfNumTypeOfElements * 3 - valuesPos := lenOfValsPos + - uint32(numOfUint8) + - uint32(numOfUint16*2) + - uint32(numOfUint32*4) + valuesPos := lenOfValsPos + numOfUint8 + numOfUint16*2 + numOfUint32*4 - addrHashMap := make(map[uint32]common.Hash, numOfUniqueItems) + incarnationPosition := lenOfValsPos + calculateIncarnationPos3(b[lenOfValsPos:], numOfUint8, numOfUint16, numOfUint32) + notDefaultIncarnation := make(map[uint32]uint64) + + if len(b) > incarnationPosition { + if len(b[incarnationPosition:])%12 != 0 { + return fmt.Errorf("decode: incarnatin part is incorrect(%d bytes)", len(b[incarnationPosition:])) + } + for i := incarnationPosition; i < len(b); i += 12 { + id := binary.BigEndian.Uint32(b[i : i+4]) + inc := ^binary.BigEndian.Uint64(b[i+4 : i+12]) + notDefaultIncarnation[id] = inc + } + } + + addrHashMap := make(map[uint32][]byte, numOfUniqueItems) for i := uint32(0); i < uint32(numOfUniqueItems); i++ { elemStart := storageEnodingStartElem + storageEnodingLengthOfDict + i*(common.HashLength) - addrHashMap[i] = common.BytesToHash(b[elemStart : elemStart+common.HashLength]) + addrHashMap[i] = b[elemStart : elemStart+common.HashLength] } key := make([]byte, common.HashLength*2+common.IncarnationLength) - elemLength := uint32(getNumOfBytesByLen(int(numOfUniqueItems))) - for i := uint32(0); i < numOfItems; i++ { + elemLength := getNumOfBytesByLen(numOfUniqueItems) + for i := 0; i < numOfItems; i++ { elemStart := storageEnodingStartElem + storageEnodingLengthOfDict + - uint32(numOfUniqueItems)*(common.HashLength) + + numOfUniqueItems*(common.HashLength) + i*(elemLength+common.HashLength) - //copy addrHash - copy(key[0:common.HashLength], readFromMap(addrHashMap, b[elemStart:elemStart+elemLength]).Bytes()) + addrIdx := getUint32(b[elemStart : elemStart+elemLength]) + copy(key[:common.HashLength], addrHashMap[addrIdx]) + if inc, ok := notDefaultIncarnation[addrIdx]; ok { + binary.BigEndian.PutUint64(key[common.HashLength:common.HashLength+common.IncarnationLength], ^inc) + } else { + binary.BigEndian.PutUint64(key[common.HashLength:common.HashLength+common.IncarnationLength], ^DefaultIncarnation) + } //copy key hash copy( key[common.HashLength+common.IncarnationLength:2*common.HashLength+common.IncarnationLength], b[elemStart+elemLength:elemStart+elemLength+common.HashLength], ) - binary.BigEndian.PutUint64(key[common.HashLength:common.HashLength+common.IncarnationLength], ^uint64(1)) err := f(common.CopyBytes(key), findVal(b[lenOfValsPos:valuesPos], b[valuesPos:], i, numOfUint8, numOfUint16, numOfUint32)) if err != nil { return err @@ -352,52 +405,50 @@ func (b StorageChangeSetBytes) Find(addrHash []byte, keyHash []byte) ([]byte, er return nil, fmt.Errorf("decode: input too short (%d bytes)", len(b)) } - numOfItems := binary.BigEndian.Uint32(b[0:storageEnodingLengthOfNumOfElements]) + numOfItems := int(binary.BigEndian.Uint32(b[:storageEnodingLengthOfNumOfElements])) if numOfItems == 0 { return nil, nil } - numOfUniqueItems := binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements : storageEnodingLengthOfNumOfElements+storageEnodingLengthOfDict]) + numOfUniqueItems := int(binary.BigEndian.Uint16(b[storageEnodingLengthOfNumOfElements:])) var addHashID uint32 found := false - var elemStart uint32 + elemStart := storageEnodingLengthOfNumOfElements + storageEnodingLengthOfDict //todo[boris] here should be binary search - for i := uint32(0); i < uint32(numOfUniqueItems); i++ { - elemStart = storageEnodingLengthOfNumOfElements + storageEnodingLengthOfDict + i*common.HashLength + for i := 0; i < numOfUniqueItems; i++ { if bytes.Equal(addrHash, b[elemStart:elemStart+common.HashLength]) { found = true - addHashID = i + addHashID = uint32(i) break } + elemStart += common.HashLength } if !found { + fmt.Printf("did not find addrHash %x\n", addrHash) return nil, ErrNotFound } + elemLength := getNumOfBytesByLen(numOfUniqueItems) lenOfValsPos := storageEnodingStartElem + storageEnodingLengthOfDict + - uint32(numOfUniqueItems)*common.HashLength + - numOfItems*uint32(getNumOfBytesByLen(int(numOfUniqueItems))+common.HashLength) + numOfUniqueItems*common.HashLength + + numOfItems*(elemLength+common.HashLength) - numOfUint8 := int(binary.BigEndian.Uint16(b[lenOfValsPos : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements])) - numOfUint16 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*2])) - numOfUint32 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*2 : lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*3])) + numOfUint8 := int(binary.BigEndian.Uint16(b[lenOfValsPos:])) + numOfUint16 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements:])) + numOfUint32 := int(binary.BigEndian.Uint16(b[lenOfValsPos+storageEnodingLengthOfNumTypeOfElements*2:])) lenOfValsPos += storageEnodingLengthOfNumTypeOfElements * 3 - valuesPos := lenOfValsPos + - uint32(numOfUint8) + - uint32(numOfUint16*2) + - uint32(numOfUint32*4) + valuesPos := lenOfValsPos + numOfUint8 + numOfUint16*2 + numOfUint32*4 //here should be binary search too - elemLength := uint32(getNumOfBytesByLen(int(numOfUniqueItems))) encodedAddHashID := make([]byte, elemLength) writeKeyRow(addHashID, encodedAddHashID) - for i := uint32(0); i < numOfItems; i++ { + for i := 0; i < numOfItems; i++ { elemStart := storageEnodingStartElem + storageEnodingLengthOfDict + - uint32(numOfUniqueItems)*(common.HashLength) + + numOfUniqueItems*(common.HashLength) + i*(elemLength+common.HashLength) if !bytes.Equal(encodedAddHashID, b[elemStart:elemStart+elemLength]) { diff --git a/common/changeset/storage_changeset_test.go b/common/changeset/storage_changeset_test.go index c7ddea801..cc9c5ffe1 100644 --- a/common/changeset/storage_changeset_test.go +++ b/common/changeset/storage_changeset_test.go @@ -3,6 +3,7 @@ package changeset import ( "bytes" "fmt" + "math/rand" "reflect" "sort" "strconv" @@ -17,7 +18,7 @@ const ( defaultIncarnation = 1 ) -func TestEncodingStorageWithoutNotDefaultIncarnation(t *testing.T) { +func TestEncodingStorageWithoutNotDefaultIncarnation1(t *testing.T) { f := func(t *testing.T, numOfElements int) { // empty StorageChangeSset first ch := NewStorageChangeSet() @@ -84,7 +85,7 @@ func TestEncodingStorageWithtRandomIncarnation(t *testing.T) { addrHash, _ := common.HashData([]byte("addrHash" + strconv.Itoa(i))) key, _ := common.HashData([]byte("key" + strconv.Itoa(i))) val, _ := common.HashData([]byte("val" + strconv.Itoa(i))) - err = ch.Add(dbutils.GenerateCompositeStorageKey(addrHash, defaultIncarnation, key), val.Bytes()) + err = ch.Add(dbutils.GenerateCompositeStorageKey(addrHash, rand.Uint64(), key), val.Bytes()) if err != nil { t.Error(err) } @@ -150,10 +151,10 @@ func TestEncodingStorageWithoutNotDefaultIncarnationWalk(t *testing.T) { i := 0 err = StorageChangeSetBytes(b).Walk(func(k, v []byte) error { if !bytes.Equal(k, ch.Changes[i].Key) { - t.Error(i, "key was incorrect", k, ch.Changes[i].Key) + t.Errorf("%d key was incorrect %x %x", i, k, ch.Changes[i].Key) } if !bytes.Equal(v, ch.Changes[i].Value) { - t.Error(i, "val is incorrect", v, ch.Changes[i].Value) + t.Errorf("%d val is incorrect %x %x", i, v, ch.Changes[i].Value) } i++ return nil @@ -202,7 +203,7 @@ func TestEncodingStorageWithoutNotDefaultIncarnationFind(t *testing.T) { t.Error(err, i) } if !bytes.Equal(val, v.Value) { - t.Error("not equal for ", v, val) + t.Errorf("not equal for %x %x", v, val) } } } diff --git a/common/dbutils/composite_keys.go b/common/dbutils/composite_keys.go index fa06e765f..4ad89e9f2 100644 --- a/common/dbutils/composite_keys.go +++ b/common/dbutils/composite_keys.go @@ -110,7 +110,7 @@ func GenerateCompositeStorageKey(addressHash common.Hash, incarnation uint64, se func GenerateStoragePrefix(addressHash common.Hash, incarnation uint64) []byte { prefix := make([]byte, common.HashLength+8) copy(prefix, addressHash[:]) - binary.BigEndian.PutUint64(prefix[common.HashLength:], incarnation^^uint64(0)) + binary.BigEndian.PutUint64(prefix[common.HashLength:], ^incarnation) return prefix } diff --git a/core/state/database.go b/core/state/database.go index 904db0903..abae6f48a 100644 --- a/core/state/database.go +++ b/core/state/database.go @@ -859,6 +859,7 @@ func (tds *TrieDbState) GetBlockNr() uint64 { } func (tds *TrieDbState) UnwindTo(blockNr uint64) error { + //fmt.Printf("Unwind from block %d to block %d\n", tds.blockNr, blockNr) tds.StartNewBuffer() b := tds.currentBuffer diff --git a/core/state/db_state_writer.go b/core/state/db_state_writer.go index a575f89ca..f06dc2e43 100644 --- a/core/state/db_state_writer.go +++ b/core/state/db_state_writer.go @@ -187,13 +187,16 @@ func (dsw *DbStateWriter) WriteHistory() error { } if debug.IsThinHistory() { for _, change := range storageChanges.Changes { - value, err1 := dsw.tds.db.Get(dbutils.StorageHistoryBucket, change.Key) + keyNoInc := make([]byte, len(change.Key)-common.IncarnationLength) + copy(keyNoInc, change.Key[:common.HashLength]) + copy(keyNoInc[common.HashLength:], change.Key[common.HashLength+common.IncarnationLength:]) + value, err1 := dsw.tds.db.Get(dbutils.StorageHistoryBucket, keyNoInc) if err1 != nil && err1 != ethdb.ErrKeyNotFound { return fmt.Errorf("db.Get failed: %w", err1) } index := dbutils.WrapHistoryIndex(value) index.Append(dsw.tds.blockNr) - if err := dsw.tds.db.Put(dbutils.StorageHistoryBucket, change.Key, *index); err != nil { + if err := dsw.tds.db.Put(dbutils.StorageHistoryBucket, keyNoInc, *index); err != nil { return err } } diff --git a/core/state/history_test.go b/core/state/history_test.go index ffc634bec..31ccfdbad 100644 --- a/core/state/history_test.go +++ b/core/state/history_test.go @@ -324,7 +324,7 @@ func TestMutationCommitThinHistory(t *testing.T) { resultHash := common.BytesToHash(res) if resultHash != v { - t.Fatal("incorrect storage history for ", addrHash.String(), v, resultHash) + t.Fatalf("incorrect storage history for %x %x %x", addrHash.String(), v, resultHash) } } } diff --git a/ethdb/bolt_db.go b/ethdb/bolt_db.go index 2044597d0..740730dd2 100644 --- a/ethdb/bolt_db.go +++ b/ethdb/bolt_db.go @@ -507,6 +507,9 @@ func (db *BoltDatabase) walkAsOfThinStorage(startkey []byte, fixedbits uint, tim if csB == nil { return fmt.Errorf("storageChangeBucket not found") } + startkeyNoInc := make([]byte, len(startkey)-common.IncarnationLength) + copy(startkeyNoInc, startkey[:common.HashLength]) + copy(startkeyNoInc[common.HashLength:], startkey[common.HashLength+common.IncarnationLength:]) //for storage mainCursor := newSplitCursor( b, @@ -518,8 +521,8 @@ func (db *BoltDatabase) walkAsOfThinStorage(startkey []byte, fixedbits uint, tim //for historic data historyCursor := newSplitCursor( hB, - startkey, - fixedbits, + startkeyNoInc, + fixedbits-8*common.IncarnationLength, common.HashLength, /* part1end */ common.HashLength+common.IncarnationLength, /* part2start */ ) @@ -912,7 +915,15 @@ func BoltDBFindByHistory(tx *bolt.Tx, hBucket []byte, key []byte, timestamp uint if hB == nil { return nil, ErrKeyNotFound } - v, _ := hB.Get(key) + var v []byte + if bytes.Equal(dbutils.StorageHistoryBucket, hBucket) { + keyNoInc := make([]byte, len(key)-common.IncarnationLength) + copy(keyNoInc, key[:common.HashLength]) + copy(keyNoInc[common.HashLength:], key[common.HashLength+common.IncarnationLength:]) + v, _ = hB.Get(keyNoInc) + } else { + v, _ = hB.Get(key) + } index := dbutils.WrapHistoryIndex(v) changeSetBlock, ok := index.Search(timestamp) @@ -933,9 +944,9 @@ func BoltDBFindByHistory(tx *bolt.Tx, hBucket []byte, key []byte, timestamp uint err error ) switch { - case debug.IsThinHistory() && bytes.Equal(dbutils.AccountsHistoryBucket, hBucket): + case bytes.Equal(dbutils.AccountsHistoryBucket, hBucket): data, err = changeset.AccountChangeSetBytes(changeSetData).FindLast(key) - case debug.IsThinHistory() && bytes.Equal(dbutils.StorageHistoryBucket, hBucket): + case bytes.Equal(dbutils.StorageHistoryBucket, hBucket): data, err = changeset.StorageChangeSetBytes(changeSetData).Find(key[:common.HashLength], key[common.HashLength+common.IncarnationLength:]) default: data, err = changeset.FindLast(changeSetData, key)