diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 6ac36da8f..c778a136b 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -45,7 +45,7 @@ import ( // Tuning parameters. const ( - version = "0.2.7" + version = "0.2.8" defaultInitialGAS = 52000000_00000000 defaultGCPeriod = 10000 @@ -1765,25 +1765,23 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti var isNEP11 = (tokenID != nil) if !isNEP11 { nep17xfer = &state.NEP17Transfer{ - Asset: id, - Amount: *amount, - From: from, - To: to, - Block: b.Index, - Timestamp: b.Timestamp, - Tx: h, + Asset: id, + Amount: amount, + Block: b.Index, + Counterparty: to, + Timestamp: b.Timestamp, + Tx: h, } transfer = nep17xfer } else { nep11xfer := &state.NEP11Transfer{ NEP17Transfer: state.NEP17Transfer{ - Asset: id, - Amount: *amount, - From: from, - To: to, - Block: b.Index, - Timestamp: b.Timestamp, - Tx: h, + Asset: id, + Amount: amount, + Block: b.Index, + Counterparty: to, + Timestamp: b.Timestamp, + Tx: h, }, ID: tokenID, } @@ -1791,14 +1789,15 @@ func (bc *Blockchain) processTokenTransfer(cache *dao.Simple, transCache map[uti nep17xfer = &nep11xfer.NEP17Transfer } if !from.Equals(util.Uint160{}) { - _ = nep17xfer.Amount.Neg(&nep17xfer.Amount) + _ = nep17xfer.Amount.Neg(nep17xfer.Amount) err := appendTokenTransfer(cache, transCache, from, transfer, id, b.Index, b.Timestamp, isNEP11) - _ = nep17xfer.Amount.Neg(&nep17xfer.Amount) + _ = nep17xfer.Amount.Neg(nep17xfer.Amount) if err != nil { return } } if !to.Equals(util.Uint160{}) { + nep17xfer.Counterparty = from _ = appendTokenTransfer(cache, transCache, to, transfer, id, b.Index, b.Timestamp, isNEP11) // Nothing useful we can do. } } diff --git a/pkg/core/state/tokens.go b/pkg/core/state/tokens.go index 8434dc298..06f7d489c 100644 --- a/pkg/core/state/tokens.go +++ b/pkg/core/state/tokens.go @@ -24,13 +24,11 @@ type TokenTransferLog struct { type NEP17Transfer struct { // Asset is a NEP-17 contract ID. Asset int32 - // Address is the address of the sender. - From util.Uint160 - // To is the address of the receiver. - To util.Uint160 + // Counterparty is the address of the sender/receiver (the other side of the transfer). + Counterparty util.Uint160 // Amount is the amount of tokens transferred. // It is negative when tokens are sent and positive if they are received. - Amount big.Int + Amount *big.Int // Block is a number of block when the event occurred. Block uint32 // Timestamp is the timestamp of the block where transfer occurred. @@ -195,11 +193,10 @@ func (t *NEP17Transfer) EncodeBinary(w *io.BinWriter) { w.WriteU32LE(uint32(t.Asset)) w.WriteBytes(t.Tx[:]) - w.WriteBytes(t.From[:]) - w.WriteBytes(t.To[:]) + w.WriteBytes(t.Counterparty[:]) w.WriteU32LE(t.Block) w.WriteU64LE(t.Timestamp) - amount := bigint.ToPreallocatedBytes(&t.Amount, buf[:]) + amount := bigint.ToPreallocatedBytes(t.Amount, buf[:]) w.WriteVarBytes(amount) } @@ -207,12 +204,11 @@ func (t *NEP17Transfer) EncodeBinary(w *io.BinWriter) { func (t *NEP17Transfer) DecodeBinary(r *io.BinReader) { t.Asset = int32(r.ReadU32LE()) r.ReadBytes(t.Tx[:]) - r.ReadBytes(t.From[:]) - r.ReadBytes(t.To[:]) + r.ReadBytes(t.Counterparty[:]) t.Block = r.ReadU32LE() t.Timestamp = r.ReadU64LE() amount := r.ReadVarBytes(bigint.MaxBytesLen) - t.Amount = *bigint.FromBytes(amount) + t.Amount = bigint.FromBytes(amount) } // EncodeBinary implements the io.Serializable interface. diff --git a/pkg/core/state/tokens_test.go b/pkg/core/state/tokens_test.go index 120b5a567..9f8f78671 100644 --- a/pkg/core/state/tokens_test.go +++ b/pkg/core/state/tokens_test.go @@ -86,13 +86,12 @@ func BenchmarkTokenTransferLog_Append(b *testing.B) { func TestNEP17Transfer_DecodeBinary(t *testing.T) { expected := &NEP17Transfer{ - Asset: 123, - From: util.Uint160{5, 6, 7}, - To: util.Uint160{8, 9, 10}, - Amount: *big.NewInt(42), - Block: 12345, - Timestamp: 54321, - Tx: util.Uint256{8, 5, 3}, + Asset: 123, + Counterparty: util.Uint160{5, 6, 7}, + Amount: big.NewInt(42), + Block: 12345, + Timestamp: 54321, + Tx: util.Uint256{8, 5, 3}, } testserdes.EncodeDecodeBinary(t, expected, new(NEP17Transfer)) @@ -101,13 +100,12 @@ func TestNEP17Transfer_DecodeBinary(t *testing.T) { func TestNEP11Transfer_DecodeBinary(t *testing.T) { expected := &NEP11Transfer{ NEP17Transfer: NEP17Transfer{ - Asset: 123, - From: util.Uint160{5, 6, 7}, - To: util.Uint160{8, 9, 10}, - Amount: *big.NewInt(42), - Block: 12345, - Timestamp: 54321, - Tx: util.Uint256{8, 5, 3}, + Asset: 123, + Counterparty: util.Uint160{5, 6, 7}, + Amount: big.NewInt(42), + Block: 12345, + Timestamp: 54321, + Tx: util.Uint256{8, 5, 3}, }, ID: []byte{42, 42, 42}, } @@ -117,24 +115,22 @@ func TestNEP11Transfer_DecodeBinary(t *testing.T) { func random17Transfer(r *rand.Rand) *NEP17Transfer { return &NEP17Transfer{ - Amount: *big.NewInt(int64(r.Uint64())), - Block: r.Uint32(), - Asset: int32(random.Int(10, 10000000)), - From: random.Uint160(), - To: random.Uint160(), - Tx: random.Uint256(), + Amount: big.NewInt(int64(r.Uint64())), + Block: r.Uint32(), + Asset: int32(random.Int(10, 10000000)), + Counterparty: random.Uint160(), + Tx: random.Uint256(), } } func random11Transfer(r *rand.Rand) *NEP11Transfer { return &NEP11Transfer{ NEP17Transfer: NEP17Transfer{ - Amount: *big.NewInt(int64(r.Uint64())), - Block: r.Uint32(), - Asset: int32(random.Int(10, 10000000)), - From: random.Uint160(), - To: random.Uint160(), - Tx: random.Uint256(), + Amount: big.NewInt(int64(r.Uint64())), + Block: r.Uint32(), + Asset: int32(random.Int(10, 10000000)), + Counterparty: random.Uint160(), + Tx: random.Uint256(), }, ID: random.Uint256().BytesBE(), } diff --git a/pkg/encoding/bigint/bench_test.go b/pkg/encoding/bigint/bench_test.go index 411a10b85..893be0118 100644 --- a/pkg/encoding/bigint/bench_test.go +++ b/pkg/encoding/bigint/bench_test.go @@ -7,9 +7,11 @@ import ( func BenchmarkToPreallocatedBytes(b *testing.B) { v := big.NewInt(100500) + vn := big.NewInt(-100500) buf := make([]byte, 4) for i := 0; i < b.N; i++ { _ = ToPreallocatedBytes(v, buf[:0]) + _ = ToPreallocatedBytes(vn, buf[:0]) } } diff --git a/pkg/encoding/bigint/bigint.go b/pkg/encoding/bigint/bigint.go index 4b9779e4a..8274bb684 100644 --- a/pkg/encoding/bigint/bigint.go +++ b/pkg/encoding/bigint/bigint.go @@ -1,6 +1,7 @@ package bigint import ( + "math" "math/big" "math/bits" @@ -113,9 +114,28 @@ func ToPreallocatedBytes(n *big.Int, data []byte) []byte { } if sign < 0 { - n.Add(n, bigOne) - defer func() { n.Sub(n, bigOne) }() - if n.Sign() == 0 { // n == -1 + bits := n.Bits() + carry := true + nonZero := false + for i := range bits { + if carry { + bits[i]-- + carry = (bits[i] == math.MaxUint) + } + nonZero = nonZero || (bits[i] != 0) + } + defer func() { + var carry = true + for i := range bits { + if carry { + bits[i]++ + carry = (bits[i] == 0) + } else { + break + } + } + }() + if !nonZero { // n == -1 return append(data[:0], 0xFF) } } diff --git a/pkg/encoding/bigint/bigint_test.go b/pkg/encoding/bigint/bigint_test.go index 79c277546..39c40d666 100644 --- a/pkg/encoding/bigint/bigint_test.go +++ b/pkg/encoding/bigint/bigint_test.go @@ -106,8 +106,14 @@ var testCases = []struct { func TestIntToBytes(t *testing.T) { for _, tc := range testCases { - buf := ToBytes(big.NewInt(tc.number)) + num := big.NewInt(tc.number) + var numC = *num // See #2864. + buf := ToBytes(num) assert.Equal(t, tc.buf, buf, "error while converting %d", tc.number) + _ = numC.Neg(&numC) + _ = ToBytes(&numC) + _ = numC.Neg(&numC) + assert.Equal(t, num, &numC, "number mismatch after converting %d", tc.number) } } diff --git a/pkg/services/rpcsrv/server.go b/pkg/services/rpcsrv/server.go index bcd89542a..6258b8ef5 100644 --- a/pkg/services/rpcsrv/server.go +++ b/pkg/services/rpcsrv/server.go @@ -1264,18 +1264,15 @@ func (s *Server) getTokenTransfers(ps params.Params, isNEP11 bool) (interface{}, Index: tr.Block, TxHash: tr.Tx, } + if !tr.Counterparty.Equals(util.Uint160{}) { + transfer.Address = address.Uint160ToString(tr.Counterparty) + } if tr.Amount.Sign() > 0 { // token was received transfer.Amount = tr.Amount.String() - if !tr.From.Equals(util.Uint160{}) { - transfer.Address = address.Uint160ToString(tr.From) - } received = &result.NEP17Transfer{} *received = transfer // Make a copy, transfer is to be modified below. } else { - transfer.Amount = new(big.Int).Neg(&tr.Amount).String() - if !tr.To.Equals(util.Uint160{}) { - transfer.Address = address.Uint160ToString(tr.To) - } + transfer.Amount = new(big.Int).Neg(tr.Amount).String() sent = &result.NEP17Transfer{} *sent = transfer }