Skip to content

Commit

Permalink
Merge pull request #173 from xssnick/dev-v19
Browse files Browse the repository at this point in the history
v1.9
  • Loading branch information
xssnick authored Mar 18, 2024
2 parents 9893120 + 8f955e0 commit d1d6074
Show file tree
Hide file tree
Showing 68 changed files with 4,071 additions and 1,987 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
filename: coverage.out

- name: Verify Changed files
uses: tj-actions/verify-changed-files@v9.1
uses: tj-actions/verify-changed-files@v17
id: verify-changed-files
with:
files: README.md
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<img align="right" width="425px" src="https://github.com/xssnick/props/blob/master/logoimg.png?raw=true">

[![Based on TON][ton-svg]][ton]
![Coverage](https://img.shields.io/badge/Coverage-73.3%25-brightgreen)
![Coverage](https://img.shields.io/badge/Coverage-74.3%25-brightgreen)

Golang library for interacting with TON blockchain.

Expand Down
76 changes: 73 additions & 3 deletions address/addr.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package address
import (
"encoding/base64"
"encoding/binary"
"encoding/hex"
"errors"
"fmt"

Expand Down Expand Up @@ -93,10 +94,22 @@ func (a *Address) String() string {
binary.BigEndian.PutUint16(address[34:], crc16.Checksum(address[:34], crcTable))
return base64.RawURLEncoding.EncodeToString(address[:])
case ExtAddress:
// TODO support readable serialization
return "EXT_ADDRESS"
address := make([]byte, 1+4+len(a.data))

address[0] = a.FlagsToByte()
binary.BigEndian.PutUint32(address[1:], uint32(a.bitsLen))
copy(address[5:], a.data)

return fmt.Sprintf("EXT:%s", hex.EncodeToString(address))
case VarAddress:
return "VAR_ADDRESS"
address := make([]byte, 1+4+4+len(a.data))

address[0] = a.FlagsToByte()
binary.BigEndian.PutUint32(address[1:], uint32(a.workchain))
binary.BigEndian.PutUint32(address[5:], uint32(a.bitsLen))
copy(address[9:], a.data)

return fmt.Sprintf("VAR:%s", hex.EncodeToString(address))
default:
return "NOT_SUPPORTED"
}
Expand Down Expand Up @@ -128,6 +141,63 @@ func (a *Address) MarshalJSON() ([]byte, error) {
return []byte(fmt.Sprintf("%q", a.String())), nil
}

func (a *Address) UnmarshalJSON(data []byte) error {
if len(data) < 2 || data[0] != '"' || data[len(data)-1] != '"' {
return fmt.Errorf("invalid data")
}

data = data[1 : len(data)-1]
strData := string(data)

var (
addr *Address
err error
)

if strData == "NONE" {
addr = NewAddressNone()
} else if strData == "NOT_SUPPORTED" {
return fmt.Errorf("not supported address")
} else if len(strData) >= 9 && strData[:4] == "EXT:" {
strData = strData[4:]

b, err := hex.DecodeString(strData)
if err != nil {
return err
}

addr = NewAddressExt(
b[0],
uint(binary.BigEndian.Uint32(b[1:5])),
b[5:],
)

} else if len(strData) >= 13 && strData[:4] == "VAR:" {
strData = strData[4:]

b, err := hex.DecodeString(strData)
if err != nil {
return err
}

addr = NewAddressVar(
b[0],
int32(binary.BigEndian.Uint32(b[1:5])),
uint(binary.BigEndian.Uint32(b[5:9])),
b[9:],
)
} else {
addr, err = ParseAddr(strData)
if err != nil {
return err
}
}

*a = *addr

return nil
}

func MustParseAddr(addr string) *Address {
a, err := ParseAddr(addr)
if err != nil {
Expand Down
226 changes: 226 additions & 0 deletions address/addr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -461,3 +461,229 @@ func TestParseflags(t *testing.T) {
})
}
}

func TestAddress_MarshalJSON(t *testing.T) {
tests := []struct {
name string
address *Address
want string
wantErr bool
}{
{
name: "none",
address: NewAddressNone(),
want: "\"NONE\"",
wantErr: false,
},
{
name: "std address",
address: MustParseAddr("EQCTDVUzmAq6EfzYGEWpVOv16yo-H5Vw3B0rktcidz_ULOUj"),
want: "\"EQCTDVUzmAq6EfzYGEWpVOv16yo-H5Vw3B0rktcidz_ULOUj\"",
wantErr: false,
},
{
name: "ext address",
address: &Address{
flags: flags{
bounceable: true,
testnet: false,
},
addrType: ExtAddress,
workchain: 0,
bitsLen: 256,
data: []byte{1, 2, 3},
},
want: "\"EXT:1100000100010203\"",
wantErr: false,
},
{
name: "ext address with empty data",
address: &Address{
flags: flags{
bounceable: true,
testnet: false,
},
addrType: ExtAddress,
workchain: 0,
bitsLen: 256,
data: nil,
},
want: "\"EXT:1100000100\"",
wantErr: false,
},
{
name: "var address",
address: &Address{
flags: flags{
bounceable: true,
testnet: true,
},
addrType: VarAddress,
workchain: -1,
bitsLen: 256,
data: []byte{4, 5, 6},
},
want: "\"VAR:91ffffffff00000100040506\"",
wantErr: false,
},
{
name: "var address with empty data",
address: &Address{
flags: flags{
bounceable: true,
testnet: true,
},
addrType: VarAddress,
workchain: -1,
bitsLen: 256,
data: nil,
},
want: "\"VAR:91ffffffff00000100\"",
wantErr: false,
},
{
name: "not supported type",
address: &Address{addrType: 5},
want: "\"NOT_SUPPORTED\"",
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := tt.address.MarshalJSON()
if (err != nil) != tt.wantErr {
t.Errorf("MarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
return
}

wantBytes := []byte(tt.want)
if !reflect.DeepEqual(got, wantBytes) {
t.Errorf("MarshalJSON() got = %v, want %v", string(got), tt.want)
}
})
}
}

func TestAddress_UnmarshalJSON(t *testing.T) {
tests := []struct {
name string
address string
want Address
wantErr bool
}{
{
name: "invalid empty",
address: "",
want: Address{},
wantErr: true,
},
{
name: "empty",
address: "\"\"",
want: Address{},
wantErr: true,
},
{
name: "valid",
address: "\"EQC6KV4zs8TJtSZapOrRFmqSkxzpq-oSCoxekQRKElf4nC1I\"",
want: Address{
addrType: StdAddress,
bitsLen: 256,
flags: flags{bounceable: true, testnet: false},
workchain: 0,
data: []byte{186, 41, 94, 51, 179, 196, 201, 181, 38, 90, 164, 234, 209, 22, 106, 146, 147, 28, 233, 171, 234, 18, 10, 140, 94, 145, 4, 74, 18, 87, 248, 156},
},
wantErr: false,
},
{
name: "invalid",
address: "\"AQCTDVUzmAq6EfzYGEWpVOv16yo-H5Vw3B0rktcidz_ULOUj\"",
want: Address{},
wantErr: true,
},
{
name: "none address",
address: "\"NONE\"",
want: Address{
addrType: NoneAddress,
},
wantErr: false,
},
{
name: "ext address",
address: "\"EXT:1100000100010203\"",
want: Address{
flags: flags{
bounceable: true,
testnet: false,
},
addrType: ExtAddress,
workchain: 0,
bitsLen: 256,
data: []byte{1, 2, 3},
},
wantErr: false,
},
{
name: "ext address with empty data",
address: "\"EXT:1100000100\"",
want: Address{
flags: flags{
bounceable: true,
testnet: false,
},
addrType: ExtAddress,
workchain: 0,
bitsLen: 256,
data: []byte{},
},
wantErr: false,
},
{
name: "var address",
address: "\"VAR:91ffffffff00000100040506\"",
want: Address{
flags: flags{
bounceable: true,
testnet: true,
},
addrType: VarAddress,
workchain: -1,
bitsLen: 256,
data: []byte{4, 5, 6},
},
wantErr: false,
},
{
name: "var address with empty data",
address: "\"VAR:91ffffffff00000100\"",
want: Address{
flags: flags{
bounceable: true,
testnet: true,
},
addrType: VarAddress,
workchain: -1,
bitsLen: 256,
data: []byte{},
},
wantErr: false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var a Address

err := a.UnmarshalJSON([]byte(tt.address))
if (err != nil) != tt.wantErr {
t.Errorf("UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr)
}

if !reflect.DeepEqual(a, tt.want) {
t.Errorf("UnmarshalJSON() got = %v, want %v", a, tt.want)
}
})
}
}
Loading

0 comments on commit d1d6074

Please sign in to comment.