Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix storage encoding #3130

Merged
merged 5 commits into from
Feb 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 55 additions & 13 deletions src/Neo/SmartContract/KeyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

using Neo.IO;
using System;
using System.Buffers.Binary;
using System.IO;

namespace Neo.SmartContract
Expand All @@ -29,8 +30,22 @@ public class KeyBuilder
/// <param name="prefix">The prefix of the key.</param>
public KeyBuilder(int id, byte prefix)
{
Add(id);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jim8y The bug was here, it was stored in the OS format, but it was readed in LittleEndian, in our test is the same, but in a BigEndian machine, it will fault.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its still wrong. You need to check the machine. Use

if (BitConverter.IsLittleEndian)
    Id = BinaryPrimitives.ReadInt32LittleEndian(cache);
else
    Id = BinaryPrimitives.ReadInt32BigEndian(cache);

this.stream.WriteByte(prefix);
var data = new byte[sizeof(int)];
BinaryPrimitives.WriteInt32LittleEndian(data, id);

stream.Write(data);
stream.WriteByte(prefix);
}

/// <summary>
/// Adds part of the key to the builder.
/// </summary>
/// <param name="key">Part of the key.</param>
/// <returns>A reference to this instance after the add operation has completed.</returns>
public KeyBuilder Add(byte key)
{
stream.WriteByte(key);
return this;
}

/// <summary>
Expand Down Expand Up @@ -60,28 +75,55 @@ public KeyBuilder Add(ISerializable key)
}

/// <summary>
/// Adds part of the key to the builder.
/// Adds part of the key to the builder in BigEndian.
/// </summary>
/// <typeparam name="T">The type of the <paramref name="key"/> parameter.</typeparam>
/// <param name="key">Part of the key.</param>
/// <returns>A reference to this instance after the add operation has completed.</returns>
unsafe public KeyBuilder Add<T>(T key) where T : unmanaged
public KeyBuilder AddBigEndian(int key)
{
return Add(new ReadOnlySpan<byte>(&key, sizeof(T)));
var data = new byte[sizeof(int)];
BinaryPrimitives.WriteInt32BigEndian(data, key);

return Add(data);
}

/// <summary>
/// Adds part of the key to the builder with big-endian.
/// Adds part of the key to the builder in BigEndian.
/// </summary>
/// <typeparam name="T">The type of the <paramref name="key"/> parameter.</typeparam>
/// <param name="key">Part of the key.</param>
/// <returns>A reference to this instance after the add operation has completed.</returns>
unsafe public KeyBuilder AddBigEndian<T>(T key) where T : unmanaged
public KeyBuilder AddBigEndian(uint key)
{
ReadOnlySpan<byte> buffer = new(&key, sizeof(T));
for (int i = buffer.Length - 1; i >= 0; i--)
stream.WriteByte(buffer[i]);
return this;
var data = new byte[sizeof(uint)];
BinaryPrimitives.WriteUInt32BigEndian(data, key);

return Add(data);
}

/// <summary>
/// Adds part of the key to the builder in BigEndian.
/// </summary>
/// <param name="key">Part of the key.</param>
/// <returns>A reference to this instance after the add operation has completed.</returns>
public KeyBuilder AddBigEndian(long key)
{
var data = new byte[sizeof(long)];
BinaryPrimitives.WriteInt64BigEndian(data, key);

return Add(data);
}

/// <summary>
/// Adds part of the key to the builder in BigEndian.
/// </summary>
/// <param name="key">Part of the key.</param>
/// <returns>A reference to this instance after the add operation has completed.</returns>
public KeyBuilder AddBigEndian(ulong key)
{
var data = new byte[sizeof(ulong)];
BinaryPrimitives.WriteUInt64BigEndian(data, key);

return Add(data);
}

/// <summary>
Expand Down
11 changes: 3 additions & 8 deletions tests/Neo.UnitTests/SmartContract/UT_KeyBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,6 @@ namespace Neo.UnitTests.SmartContract
[TestClass]
public class UT_KeyBuilder
{
private struct TestKey
{
public int Value;
}

[TestMethod]
public void Test()
{
Expand All @@ -39,11 +34,11 @@ public void Test()
Assert.AreEqual("010000000203040000000000000000000000000000000000000000", key.ToArray().ToHexString());

key = new KeyBuilder(1, 2);
key = key.Add(new TestKey { Value = 123 });
Assert.AreEqual("01000000027b000000", key.ToArray().ToHexString());
key = key.AddBigEndian(123);
Assert.AreEqual("01000000020000007b", key.ToArray().ToHexString());

key = new KeyBuilder(1, 0);
key = key.AddBigEndian(new TestKey { Value = 1 });
key = key.AddBigEndian(1);
Assert.AreEqual("010000000000000001", key.ToArray().ToHexString());
}
}
Expand Down