Commit b862b61d authored by vipwzw's avatar vipwzw Committed by 33cn

update 2019 05/06

parent 67ea246e
...@@ -18,6 +18,7 @@ build/relayd ...@@ -18,6 +18,7 @@ build/relayd
build/relayd.toml build/relayd.toml
build/*.log build/*.log
build/fzm build/fzm
build/*.db
build/guodun build/guodun
build/main.sh build/main.sh
build/main* build/main*
......
...@@ -161,6 +161,7 @@ func NewBlockStore(chain *BlockChain, db dbm.DB, client queue.Client) *BlockStor ...@@ -161,6 +161,7 @@ func NewBlockStore(chain *BlockChain, db dbm.DB, client queue.Client) *BlockStor
//3. 2000个交易处理一次,并且打印进度 //3. 2000个交易处理一次,并且打印进度
//4. 全部处理完成了,添加quickIndex 的标记 //4. 全部处理完成了,添加quickIndex 的标记
func (bs *BlockStore) initQuickIndex(height int64) { func (bs *BlockStore) initQuickIndex(height int64) {
storeLog.Info("quickIndex upgrade start", "current height", height)
batch := bs.db.NewBatch(true) batch := bs.db.NewBatch(true)
var maxsize = 100 * 1024 * 1024 var maxsize = 100 * 1024 * 1024
var count = 0 var count = 0
......
...@@ -15,7 +15,9 @@ import ( ...@@ -15,7 +15,9 @@ import (
// Upgrade 升级localDB和storeDB // Upgrade 升级localDB和storeDB
func (chain *BlockChain) Upgrade() { func (chain *BlockChain) Upgrade() {
chainlog.Info("chain upgrade start")
chain.UpgradeChain() chain.UpgradeChain()
chainlog.Info("storedb upgrade start")
chain.UpgradeStore() chain.UpgradeStore()
} }
......
...@@ -224,6 +224,7 @@ ForkMultiSignAddress=1298600 ...@@ -224,6 +224,7 @@ ForkMultiSignAddress=1298600
ForkTxHeight= -1 ForkTxHeight= -1
ForkTxGroupPara= -1 ForkTxGroupPara= -1
ForkChainParamV2= -1 ForkChainParamV2= -1
ForkBase58AddressCheck=1800000
[fork.sub.coins] [fork.sub.coins]
Enable=0 Enable=0
[fork.sub.ticket] [fork.sub.ticket]
......
...@@ -7,6 +7,7 @@ package address ...@@ -7,6 +7,7 @@ package address
import ( import (
"bytes" "bytes"
"crypto/sha256"
"encoding/hex" "encoding/hex"
"errors" "errors"
...@@ -28,6 +29,9 @@ var ErrCheckVersion = errors.New("check version error") ...@@ -28,6 +29,9 @@ var ErrCheckVersion = errors.New("check version error")
//ErrCheckChecksum : //ErrCheckChecksum :
var ErrCheckChecksum = errors.New("Address Checksum error") var ErrCheckChecksum = errors.New("Address Checksum error")
//ErrAddressChecksum :
var ErrAddressChecksum = errors.New("address checksum error")
//MaxExecNameLength 执行器名最大长度 //MaxExecNameLength 执行器名最大长度
const MaxExecNameLength = 100 const MaxExecNameLength = 100
...@@ -139,7 +143,15 @@ func HashToAddress(version byte, in []byte) *Address { ...@@ -139,7 +143,15 @@ func HashToAddress(version byte, in []byte) *Address {
return a return a
} }
func checksum(input []byte) (cksum [4]byte) {
h := sha256.Sum256(input)
h2 := sha256.Sum256(h[:])
copy(cksum[:], h2[:4])
return
}
func checkAddress(ver byte, addr string) (e error) { func checkAddress(ver byte, addr string) (e error) {
dec := base58.Decode(addr) dec := base58.Decode(addr)
if dec == nil { if dec == nil {
e = errors.New("Cannot decode b58 string '" + addr + "'") e = errors.New("Cannot decode b58 string '" + addr + "'")
...@@ -151,14 +163,24 @@ func checkAddress(ver byte, addr string) (e error) { ...@@ -151,14 +163,24 @@ func checkAddress(ver byte, addr string) (e error) {
checkAddressCache.Add(addr, e) checkAddressCache.Add(addr, e)
return return
} }
//version 的错误优先
if dec[0] != ver {
e = ErrCheckVersion
return
}
//需要兼容以前的错误(以前的错误,是一种特殊的情况)
if len(dec) == 25 { if len(dec) == 25 {
sh := common.Sha2Sum(dec[0:21]) sh := common.Sha2Sum(dec[0:21])
if !bytes.Equal(sh[:4], dec[21:25]) { if !bytes.Equal(sh[:4], dec[21:25]) {
e = ErrCheckChecksum e = ErrCheckChecksum
return
} }
} }
if dec[0] != ver { var cksum [4]byte
e = ErrCheckVersion copy(cksum[:], dec[len(dec)-4:])
//新的错误: 这个错误用一种新的错误标记
if checksum(dec[:len(dec)-4]) != cksum {
e = ErrAddressChecksum
} }
return e return e
} }
......
...@@ -73,6 +73,9 @@ func TestCheckAddress(t *testing.T) { ...@@ -73,6 +73,9 @@ func TestCheckAddress(t *testing.T) {
addr := PubKeyToAddress(key.PubKey().Bytes()) addr := PubKeyToAddress(key.PubKey().Bytes())
err = CheckAddress(addr.String()) err = CheckAddress(addr.String())
require.NoError(t, err) require.NoError(t, err)
err = CheckAddress(addr.String() + addr.String())
require.Equal(t, err, ErrAddressChecksum)
} }
func TestExecAddress(t *testing.T) { func TestExecAddress(t *testing.T) {
......
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package p256 implements a verifiable random function using curve p256.
package p256
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/hmac"
"crypto/rand"
"crypto/sha256"
"crypto/sha512"
"encoding/binary"
"errors"
"math/big"
vrfp "github.com/33cn/chain33/common/vrf"
)
var (
curve = elliptic.P256()
params = curve.Params()
// ErrInvalidVRF err
ErrInvalidVRF = errors.New("invalid VRF proof")
)
// PublicKey holds a public VRF key.
type PublicKey struct {
*ecdsa.PublicKey
}
// PrivateKey holds a private VRF key.
type PrivateKey struct {
*ecdsa.PrivateKey
}
// GenerateKey generates a fresh keypair for this VRF
func GenerateKey() (vrfp.PrivateKey, vrfp.PublicKey) {
key, err := ecdsa.GenerateKey(curve, rand.Reader)
if err != nil {
return nil, nil
}
return &PrivateKey{PrivateKey: key}, &PublicKey{PublicKey: &key.PublicKey}
}
// H1 hashes m to a curve point
func H1(m []byte) (x, y *big.Int) {
h := sha512.New()
var i uint32
byteLen := (params.BitSize + 7) >> 3
for x == nil && i < 100 {
// TODO: Use a NIST specified DRBG.
h.Reset()
if err := binary.Write(h, binary.BigEndian, i); err != nil {
panic(err)
}
if _, err := h.Write(m); err != nil {
panic(err)
}
r := []byte{2} // Set point encoding to "compressed", y=0.
r = h.Sum(r)
x, y = Unmarshal(curve, r[:byteLen+1])
i++
}
return
}
var one = big.NewInt(1)
// H2 hashes to an integer [1,N-1]
func H2(m []byte) *big.Int {
// NIST SP 800-90A § A.5.1: Simple discard method.
byteLen := (params.BitSize + 7) >> 3
h := sha512.New()
for i := uint32(0); ; i++ {
// TODO: Use a NIST specified DRBG.
h.Reset()
if err := binary.Write(h, binary.BigEndian, i); err != nil {
panic(err)
}
if _, err := h.Write(m); err != nil {
panic(err)
}
b := h.Sum(nil)
k := new(big.Int).SetBytes(b[:byteLen])
if k.Cmp(new(big.Int).Sub(params.N, one)) == -1 {
return k.Add(k, one)
}
}
}
// Evaluate returns the verifiable unpredictable function evaluated at m
func (k PrivateKey) Evaluate(m []byte) (index [32]byte, proof []byte) {
nilIndex := [32]byte{}
// Prover chooses r <-- [1,N-1]
r, _, _, err := elliptic.GenerateKey(curve, rand.Reader)
if err != nil {
return nilIndex, nil
}
ri := new(big.Int).SetBytes(r)
// H = H1(m)
Hx, Hy := H1(m)
// VRF_k(m) = [k]H
sHx, sHy := params.ScalarMult(Hx, Hy, k.D.Bytes())
vrf := elliptic.Marshal(curve, sHx, sHy) // 65 bytes.
// G is the base point
// s = H2(G, H, [k]G, VRF, [r]G, [r]H)
rGx, rGy := params.ScalarBaseMult(r)
rHx, rHy := params.ScalarMult(Hx, Hy, r)
var b bytes.Buffer
if _, err := b.Write(elliptic.Marshal(curve, params.Gx, params.Gy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, Hx, Hy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, k.PublicKey.X, k.PublicKey.Y)); err != nil {
panic(err)
}
if _, err := b.Write(vrf); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, rGx, rGy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, rHx, rHy)); err != nil {
panic(err)
}
s := H2(b.Bytes())
// t = r−s*k mod N
t := new(big.Int).Sub(ri, new(big.Int).Mul(s, k.D))
t.Mod(t, params.N)
// Index = H(vrf)
index = sha256.Sum256(vrf)
// Write s, t, and vrf to a proof blob. Also write leading zeros before s and t
// if needed.
var buf bytes.Buffer
if _, err := buf.Write(make([]byte, 32-len(s.Bytes()))); err != nil {
panic(err)
}
if _, err := buf.Write(s.Bytes()); err != nil {
panic(err)
}
if _, err := buf.Write(make([]byte, 32-len(t.Bytes()))); err != nil {
panic(err)
}
if _, err := buf.Write(t.Bytes()); err != nil {
panic(err)
}
if _, err := buf.Write(vrf); err != nil {
panic(err)
}
return index, buf.Bytes()
}
// ProofToHash asserts that proof is correct for m and outputs index.
func (pk *PublicKey) ProofToHash(m, proof []byte) (index [32]byte, err error) {
nilIndex := [32]byte{}
// verifier checks that s == H2(m, [t]G + [s]([k]G), [t]H1(m) + [s]VRF_k(m))
if got, want := len(proof), 64+65; got != want {
return nilIndex, ErrInvalidVRF
}
// Parse proof into s, t, and vrf.
s := proof[0:32]
t := proof[32:64]
vrf := proof[64 : 64+65]
uHx, uHy := elliptic.Unmarshal(curve, vrf)
if uHx == nil {
return nilIndex, ErrInvalidVRF
}
// [t]G + [s]([k]G) = [t+ks]G
tGx, tGy := params.ScalarBaseMult(t)
ksGx, ksGy := params.ScalarMult(pk.X, pk.Y, s)
tksGx, tksGy := params.Add(tGx, tGy, ksGx, ksGy)
// H = H1(m)
// [t]H + [s]VRF = [t+ks]H
Hx, Hy := H1(m)
tHx, tHy := params.ScalarMult(Hx, Hy, t)
sHx, sHy := params.ScalarMult(uHx, uHy, s)
tksHx, tksHy := params.Add(tHx, tHy, sHx, sHy)
// H2(G, H, [k]G, VRF, [t]G + [s]([k]G), [t]H + [s]VRF)
// = H2(G, H, [k]G, VRF, [t+ks]G, [t+ks]H)
// = H2(G, H, [k]G, VRF, [r]G, [r]H)
var b bytes.Buffer
if _, err := b.Write(elliptic.Marshal(curve, params.Gx, params.Gy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, Hx, Hy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, pk.X, pk.Y)); err != nil {
panic(err)
}
if _, err := b.Write(vrf); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, tksGx, tksGy)); err != nil {
panic(err)
}
if _, err := b.Write(elliptic.Marshal(curve, tksHx, tksHy)); err != nil {
panic(err)
}
h2 := H2(b.Bytes())
// Left pad h2 with zeros if needed. This will ensure that h2 is padded
// the same way s is.
var buf bytes.Buffer
if _, err := buf.Write(make([]byte, 32-len(h2.Bytes()))); err != nil {
panic(err)
}
if _, err := buf.Write(h2.Bytes()); err != nil {
panic(err)
}
if !hmac.Equal(s, buf.Bytes()) {
return nilIndex, ErrInvalidVRF
}
return sha256.Sum256(vrf), nil
}
// Public returns the corresponding public key as bytes.
func (k PrivateKey) Public() crypto.PublicKey {
return &k.PublicKey
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p256
import (
"crypto/elliptic"
"math/big"
)
// Unmarshal a compressed point in the form specified in section 4.3.6 of ANSI X9.62.
func Unmarshal(curve elliptic.Curve, data []byte) (x, y *big.Int) {
byteLen := (curve.Params().BitSize + 7) >> 3
if (data[0] &^ 1) != 2 {
return // unrecognized point encoding
}
if len(data) != 1+byteLen {
return
}
// Based on Routine 2.2.4 in NIST Mathematical routines paper
params := curve.Params()
tx := new(big.Int).SetBytes(data[1 : 1+byteLen])
y2 := y2(params, tx)
sqrt := defaultSqrt
ty := sqrt(y2, params.P)
if ty == nil {
return // "y^2" is not a square: invalid point
}
var y2c big.Int
y2c.Mul(ty, ty).Mod(&y2c, params.P)
if y2c.Cmp(y2) != 0 {
return // sqrt(y2)^2 != y2: invalid point
}
if ty.Bit(0) != uint(data[0]&1) {
ty.Sub(params.P, ty)
}
x, y = tx, ty // valid point: return it
return
}
// Use the curve equation to calculate y² given x.
// only applies to curves of the form y² = x³ - 3x + b.
func y2(curve *elliptic.CurveParams, x *big.Int) *big.Int {
// y² = x³ - 3x + b
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
threeX := new(big.Int).Lsh(x, 1)
threeX.Add(threeX, x)
x3.Sub(x3, threeX)
x3.Add(x3, curve.B)
x3.Mod(x3, curve.P)
return x3
}
func defaultSqrt(x, p *big.Int) *big.Int {
var r big.Int
if nil == r.ModSqrt(x, p) {
return nil // x is not a square
}
return &r
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p256
import (
"crypto/ecdsa"
"crypto/elliptic"
"errors"
"math/big"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/vrf"
)
// GenVrfKey returns vrf private and public key
func GenVrfKey(key crypto.PrivKey) (vrf.PrivateKey, vrf.PublicKey, []byte) {
priv, pub := PrivKeyFromBytes(elliptic.P256(), key.Bytes())
return &PrivateKey{PrivateKey: priv}, &PublicKey{PublicKey: pub}, SerializePublicKey(pub)
}
// PrivKeyFromBytes return ecdsa private and public key
func PrivKeyFromBytes(curve elliptic.Curve, pk []byte) (*ecdsa.PrivateKey, *ecdsa.PublicKey) {
x, y := curve.ScalarBaseMult(pk)
priv := &ecdsa.PrivateKey{
PublicKey: ecdsa.PublicKey{
Curve: curve,
X: x,
Y: y,
},
D: new(big.Int).SetBytes(pk),
}
return priv, &priv.PublicKey
}
// SerializePublicKey serialize public key
func SerializePublicKey(p *ecdsa.PublicKey) []byte {
b := make([]byte, 0, 65)
b = append(b, 0x4)
b = paddedAppend(32, b, p.X.Bytes())
return paddedAppend(32, b, p.Y.Bytes())
}
func paddedAppend(size uint, dst, src []byte) []byte {
for i := 0; i < int(size)-len(src); i++ {
dst = append(dst, 0)
}
return append(dst, src...)
}
// ParseVrfPubKey parse public key
func ParseVrfPubKey(pubKeyStr []byte) (vrf.PublicKey, error) {
pubkey := &ecdsa.PublicKey{}
pubkey.Curve = elliptic.P256()
if len(pubKeyStr) == 0 {
return nil, errors.New("pubkey string is empty")
}
pubkey.X = new(big.Int).SetBytes(pubKeyStr[1:33])
pubkey.Y = new(big.Int).SetBytes(pubKeyStr[33:])
if pubkey.X.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, errors.New("pubkey X parameter is >= to P")
}
if pubkey.Y.Cmp(pubkey.Curve.Params().P) >= 0 {
return nil, errors.New("pubkey Y parameter is >= to P")
}
if !pubkey.Curve.IsOnCurve(pubkey.X, pubkey.Y) {
return nil, errors.New("pubkey isn't on secp256k1 curve")
}
return &PublicKey{PublicKey: pubkey}, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package p256
import (
"testing"
"github.com/33cn/chain33/common/crypto"
"github.com/33cn/chain33/common/vrf"
"github.com/33cn/chain33/types"
"github.com/stretchr/testify/assert"
)
func Test_GenerateKey(t *testing.T) {
k, pk := GenerateKey()
testVRF(t, k, pk)
}
func Test_GenVrfKey(t *testing.T) {
c, err := crypto.New(types.GetSignName("", types.SECP256K1))
assert.NoError(t, err)
priv, err := c.GenKey()
assert.NoError(t, err)
vpriv, _, pubKey := GenVrfKey(priv)
vpub, err := ParseVrfPubKey(pubKey)
assert.NoError(t, err)
testVRF(t, vpriv, vpub)
}
func testVRF(t *testing.T, priv vrf.PrivateKey, pub vrf.PublicKey) {
m1 := []byte("data1")
m2 := []byte("data2")
m3 := []byte("data2")
hash1, proof1 := priv.Evaluate(m1)
hash2, proof2 := priv.Evaluate(m2)
hash3, proof3 := priv.Evaluate(m3)
for _, tc := range []struct {
m []byte
hash [32]byte
proof []byte
err error
}{
{m1, hash1, proof1, nil},
{m2, hash2, proof2, nil},
{m3, hash3, proof3, nil},
{m3, hash3, proof2, nil},
{m3, hash3, proof1, ErrInvalidVRF},
} {
hash, err := pub.ProofToHash(tc.m, tc.proof)
if got, want := err, tc.err; got != want {
t.Errorf("ProofToHash(%s, %x): %v, want %v", tc.m, tc.proof, got, want)
}
if err != nil {
continue
}
if got, want := hash, tc.hash; got != want {
t.Errorf("ProofToHash(%s, %x): %x, want %x", tc.m, tc.proof, got, want)
}
}
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package vrf defines the interface to a verifiable random function.
package vrf
import (
"crypto"
)
// A VRF is a pseudorandom function f_k from a secret key k, such that that
// knowledge of k not only enables one to evaluate f_k at for any message m,
// but also to provide an NP-proof that the value f_k(m) is indeed correct
// without compromising the unpredictability of f_k for any m' != m.
// PrivateKey supports evaluating the VRF function.
type PrivateKey interface {
// Evaluate returns the output of H(f_k(m)) and its proof.
Evaluate(m []byte) (index [32]byte, proof []byte)
// Public returns the corresponding public key.
Public() crypto.PublicKey
}
// PublicKey supports verifying output from the VRF function.
type PublicKey interface {
// ProofToHash verifies the NP-proof supplied by Proof and outputs Index.
ProofToHash(m, proof []byte) (index [32]byte, err error)
}
...@@ -45,6 +45,12 @@ func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, err ...@@ -45,6 +45,12 @@ func (c *channelClient) CreateRawTransaction(param *types.CreateTx) ([]byte, err
log.Error("CreateRawTransaction", "Error", types.ErrInvalidParam) log.Error("CreateRawTransaction", "Error", types.ErrInvalidParam)
return nil, types.ErrInvalidParam return nil, types.ErrInvalidParam
} }
//构建交易时to地址不为空时需要检测地址的合法性
if param.GetTo() != "" {
if err := address.CheckAddress(param.GetTo()); err != nil {
return nil, types.ErrInvalidAddress
}
}
//因为历史原因,这里还是有部分token 的字段,但是没有依赖token dapp //因为历史原因,这里还是有部分token 的字段,但是没有依赖token dapp
//未来这个调用可能会被废弃 //未来这个调用可能会被废弃
execer := types.ExecName(ety.CoinsX) execer := types.ExecName(ety.CoinsX)
...@@ -70,18 +76,61 @@ func (c *channelClient) ReWriteRawTx(param *types.ReWriteRawTx) ([]byte, error) ...@@ -70,18 +76,61 @@ func (c *channelClient) ReWriteRawTx(param *types.ReWriteRawTx) ([]byte, error)
if param.To != "" { if param.To != "" {
tx.To = param.To tx.To = param.To
} }
if param.Fee != 0 { if param.Fee != 0 && param.Fee > tx.Fee {
tx.Fee = param.Fee tx.Fee = param.Fee
} }
var expire int64
if param.Expire != "" { if param.Expire != "" {
expire, err := types.ParseExpire(param.Expire) expire, err = types.ParseExpire(param.Expire)
if err != nil { if err != nil {
return nil, err return nil, err
} }
tx.Expire = expire tx.SetExpire(time.Duration(expire))
}
group, err := tx.GetTxGroup()
if err != nil {
return nil, err
}
//单笔交易直接返回
if group == nil {
txHex := types.Encode(tx)
return txHex, nil
} }
return types.FormatTxEncode(string(tx.Execer), tx) //交易组的处理
index := param.Index
if int(index) > len(group.GetTxs()) {
return nil, types.ErrIndex
}
//修改交易组中所有成员交易
if index <= 0 {
if param.Fee != 0 && param.Fee > group.Txs[0].Fee {
group.Txs[0].Fee = param.Fee
}
if param.Expire != "" {
for i := 0; i < len(group.Txs); i++ {
group.SetExpire(i, time.Duration(expire))
}
}
group.RebuiltGroup()
grouptx := group.Tx()
txHex := types.Encode(grouptx)
return txHex, nil
}
//修改交易组中指定成员交易
index--
if param.Fee != 0 && index == 0 && param.Fee > group.Txs[0].Fee {
group.Txs[0].Fee = param.Fee
}
if param.Expire != "" {
group.SetExpire(int(index), time.Duration(expire))
}
group.RebuiltGroup()
grouptx := group.Tx()
txHex := types.Encode(grouptx)
return txHex, nil
} }
// CreateRawTxGroup create rawtransaction for group // CreateRawTxGroup create rawtransaction for group
......
...@@ -90,7 +90,7 @@ func testCreateRawTransactionCoinTransfer(t *testing.T) { ...@@ -90,7 +90,7 @@ func testCreateRawTransactionCoinTransfer(t *testing.T) {
Amount: 10, Amount: 10,
IsToken: false, IsToken: false,
IsWithdraw: false, IsWithdraw: false,
To: "to", To: "1JkbMq5yNMZHtokjg5XxkC3RZbqjoPJm84",
Note: []byte("note"), Note: []byte("note"),
} }
...@@ -113,7 +113,7 @@ func testCreateRawTransactionCoinTransferExec(t *testing.T) { ...@@ -113,7 +113,7 @@ func testCreateRawTransactionCoinTransferExec(t *testing.T) {
Amount: 10, Amount: 10,
IsToken: false, IsToken: false,
IsWithdraw: false, IsWithdraw: false,
To: "to", To: "1JkbMq5yNMZHtokjg5XxkC3RZbqjoPJm84",
Note: []byte("note"), Note: []byte("note"),
} }
...@@ -140,7 +140,7 @@ func testCreateRawTransactionCoinWithdraw(t *testing.T) { ...@@ -140,7 +140,7 @@ func testCreateRawTransactionCoinWithdraw(t *testing.T) {
Amount: 10, Amount: 10,
IsToken: false, IsToken: false,
IsWithdraw: true, IsWithdraw: true,
To: "to", To: "1JkbMq5yNMZHtokjg5XxkC3RZbqjoPJm84",
Note: []byte("note"), Note: []byte("note"),
} }
...@@ -328,3 +328,56 @@ func TestChannelClient_CreateNoBalanceTransaction(t *testing.T) { ...@@ -328,3 +328,56 @@ func TestChannelClient_CreateNoBalanceTransaction(t *testing.T) {
_, err := client.CreateNoBalanceTransaction(in) _, err := client.CreateNoBalanceTransaction(in)
assert.NoError(t, err) assert.NoError(t, err)
} }
func TestClientReWriteRawTx(t *testing.T) {
//交易组原始交易的修改测试
txHex1 := "0a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6720c0843d30aab4d59684b5cce7143a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4ab50c0aa3010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6720c0843d30aab4d59684b5cce7143a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522008217c413b035fddd8f34a303e90a29e661746ed9b23a97768c1f25817c2c3450a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a673094fbcabe96c99ea7163a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f552203c6a2b11cce466891f084b49450472b1d4c39213f63117d3d4ce2a3851304ebc0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730c187fb80fe88ce9e3c3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522066419d70492f757d7285fd226dff62da8d803c8121ded95242d222dbb10f2d9b0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a673098aa929ab292b3f0023a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f552202bab08051d24fe923f66c8aeea4ce3f425d47a72f7c5c230a2b1427e04e2eb510a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730bfe9abb3edc6d9cb163a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f55220e1ba0493aa431ea3071026bd8dfa8280efab53ce86441fc474a1c19550a554ba0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730d2e196a8ecada9d53e3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522016600fbfa23b3f0e8f9a14b716ce8f4064c091fbf6fa94489bc9d14b5b6049a60a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730a0b7b1b1dda2f4c5743a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522089d0442d76713369022499d054db65ccacbf5c627a525bd5454e0a30d23fa2990a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730c5838f94e2f49acb4b3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522018f208938606b390d752898332a84a9fbb900c2ed55ec33cd54d09b1970043b90a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a67308dfddb82faf7dfc4113a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522013002bab7a9c65881bd937a6fded4c3959bb631fa84434572970c1ec3e6fccf90a7d0a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730b8b082d799a4ddc93a3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522008217c413b035fddd8f34a303e90a29e661746ed9b23a97768c1f25817c2c345"
//修改交易组的所有交易
ctx := types.ReWriteRawTx{
Tx: txHex1,
Fee: 29977777777,
Expire: "130s",
To: "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt",
Index: 0,
}
client := newTestChannelClient()
txHex, err := client.ReWriteRawTx(&ctx)
assert.Nil(t, err)
rtTx := hex.EncodeToString(txHex)
txData, err := hex.DecodeString(rtTx)
assert.Nil(t, err)
tx := &types.Transaction{}
err = types.Decode(txData, tx)
assert.Nil(t, err)
assert.Equal(t, ctx.Fee, tx.Fee)
//只修改交易组中指定的交易
ctx2 := types.ReWriteRawTx{
Tx: txHex1,
Fee: 29977777777,
Expire: "130s",
To: "14KEKbYtKKQm4wMthSK9J4La4nAiidGozt",
Index: 2,
}
txHex22, err := client.ReWriteRawTx(&ctx2)
assert.Nil(t, err)
rtTx22 := hex.EncodeToString(txHex22)
txData22, err := hex.DecodeString(rtTx22)
assert.Nil(t, err)
tx22 := &types.Transaction{}
err = types.Decode(txData22, tx22)
assert.Nil(t, err)
group22, err := tx22.GetTxGroup()
assert.Nil(t, err)
for index, tmptx := range group22.GetTxs() {
if tmptx.GetExpire() != 0 && index != 1 {
t.Error("TestClientReWriteRawTx Expire !=0 index != 1 ")
}
if tmptx.GetFee() != 0 && index != 0 {
t.Error("TestClientReWriteRawTx Fee !=0")
}
}
}
...@@ -1055,6 +1055,7 @@ func TestReWriteRawTx(t *testing.T) { ...@@ -1055,6 +1055,7 @@ func TestReWriteRawTx(t *testing.T) {
Fee: 29977777777, Fee: 29977777777,
Expire: "130s", Expire: "130s",
To: "aabbccdd", To: "aabbccdd",
Index: 0,
} }
data, err := g.ReWriteRawTx(getOkCtx(), in) data, err := g.ReWriteRawTx(getOkCtx(), in)
...@@ -1067,7 +1068,6 @@ func TestReWriteRawTx(t *testing.T) { ...@@ -1067,7 +1068,6 @@ func TestReWriteRawTx(t *testing.T) {
err = types.Decode(data.Data, tx) err = types.Decode(data.Data, tx)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, tx.Fee, in.Fee) assert.Equal(t, tx.Fee, in.Fee)
assert.Equal(t, int64(130000000000), tx.Expire)
assert.Equal(t, in.To, tx.To) assert.Equal(t, in.To, tx.To)
} }
......
...@@ -50,6 +50,7 @@ func (c *Chain33) ReWriteRawTx(in *rpctypes.ReWriteRawTx, result *interface{}) e ...@@ -50,6 +50,7 @@ func (c *Chain33) ReWriteRawTx(in *rpctypes.ReWriteRawTx, result *interface{}) e
To: in.To, To: in.To,
Fee: in.Fee, Fee: in.Fee,
Expire: in.Expire, Expire: in.Expire,
Index: in.Index,
} }
reply, err := c.cli.ReWriteRawTx(inpb) reply, err := c.cli.ReWriteRawTx(inpb)
......
...@@ -416,6 +416,7 @@ func TestChain33_ReWriteRawTx(t *testing.T) { ...@@ -416,6 +416,7 @@ func TestChain33_ReWriteRawTx(t *testing.T) {
Fee: 29977777777, Fee: 29977777777,
Expire: "130s", Expire: "130s",
To: "aabbccdd", To: "aabbccdd",
Index: 0,
} }
var testResult interface{} var testResult interface{}
err := testChain33.ReWriteRawTx(reTx, &testResult) err := testChain33.ReWriteRawTx(reTx, &testResult)
...@@ -428,7 +429,6 @@ func TestChain33_ReWriteRawTx(t *testing.T) { ...@@ -428,7 +429,6 @@ func TestChain33_ReWriteRawTx(t *testing.T) {
err = types.Decode(txData, tx) err = types.Decode(txData, tx)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, tx.Fee, reTx.Fee) assert.Equal(t, tx.Fee, reTx.Fee)
assert.Equal(t, int64(130000000000), tx.Expire)
assert.Equal(t, reTx.To, tx.To) assert.Equal(t, reTx.To, tx.To)
} }
......
...@@ -390,4 +390,5 @@ type ReWriteRawTx struct { ...@@ -390,4 +390,5 @@ type ReWriteRawTx struct {
To string `json:"to"` To string `json:"to"`
Fee int64 `json:"fee"` Fee int64 `json:"fee"`
Expire string `json:"expire"` Expire string `json:"expire"`
Index int32 `json:"index"`
} }
...@@ -307,30 +307,37 @@ func ReWriteRawTxCmd() *cobra.Command { ...@@ -307,30 +307,37 @@ func ReWriteRawTxCmd() *cobra.Command {
func addReWriteRawTxFlags(cmd *cobra.Command) { func addReWriteRawTxFlags(cmd *cobra.Command) {
cmd.Flags().StringP("tx", "s", "", "transaction hex") cmd.Flags().StringP("tx", "s", "", "transaction hex")
cmd.MarkFlagRequired("tx") cmd.MarkFlagRequired("tx")
cmd.Flags().StringP("to", "t", "", "to addr (optional)") cmd.Flags().StringP("to", "t", "", "to addr (optional)")
cmd.Flags().Float64P("fee", "f", 0, "transaction fee (optional)") cmd.Flags().Float64P("fee", "f", 0, "transaction fee (optional)")
cmd.Flags().StringP("expire", "e", "120s", "expire time (optional)") cmd.Flags().StringP("expire", "e", "", "expire time (optional)")
cmd.Flags().Int32P("index", "i", 0, "transaction index to be signed")
} }
func reWriteRawTx(cmd *cobra.Command, args []string) { func reWriteRawTx(cmd *cobra.Command, args []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr") rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
txHash, _ := cmd.Flags().GetString("tx") txHex, _ := cmd.Flags().GetString("tx")
to, _ := cmd.Flags().GetString("to") to, _ := cmd.Flags().GetString("to")
fee, _ := cmd.Flags().GetFloat64("fee") fee, _ := cmd.Flags().GetFloat64("fee")
index, _ := cmd.Flags().GetInt32("index")
expire, _ := cmd.Flags().GetString("expire") expire, _ := cmd.Flags().GetString("expire")
expire, err := commandtypes.CheckExpireOpt(expire)
if err != nil { var err error
fmt.Fprintln(os.Stderr, err) if expire != "" {
return expire, err = commandtypes.CheckExpireOpt(expire)
if err != nil {
fmt.Fprintln(os.Stderr, err)
return
}
} }
feeInt64 := int64(fee * 1e4) feeInt64 := int64(fee * 1e4)
params := rpctypes.ReWriteRawTx{ params := rpctypes.ReWriteRawTx{
Tx: txHash, Tx: txHex,
To: to, To: to,
Fee: feeInt64 * 1e4, Fee: feeInt64 * 1e4,
Expire: expire, Expire: expire,
Index: index,
} }
ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.ReWriteRawTx", params, nil) ctx := jsonclient.NewRPCCtx(rpcLaddr, "Chain33.ReWriteRawTx", params, nil)
......
...@@ -87,7 +87,12 @@ func CreateRawTx(cmd *cobra.Command, to string, amount float64, note string, isW ...@@ -87,7 +87,12 @@ func CreateRawTx(cmd *cobra.Command, to string, amount float64, note string, isW
if float64(types.MaxCoin/types.Coin) < amount { if float64(types.MaxCoin/types.Coin) < amount {
return "", types.ErrAmount return "", types.ErrAmount
} }
//检测to地址的合法性
if to != "" {
if err := address.CheckAddress(to); err != nil {
return "", types.ErrInvalidAddress
}
}
paraName, _ := cmd.Flags().GetString("paraName") paraName, _ := cmd.Flags().GetString("paraName")
amountInt64 := int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4 amountInt64 := int64(math.Trunc((amount+0.0000001)*1e4)) * 1e4
if execName != "" && !types.IsAllowExecName([]byte(execName), []byte(execName)) { if execName != "" && !types.IsAllowExecName([]byte(execName), []byte(execName)) {
......
...@@ -284,6 +284,10 @@ func CheckAddress(addr string, height int64) error { ...@@ -284,6 +284,10 @@ func CheckAddress(addr string, height int64) error {
if !types.IsFork(height, "ForkMultiSignAddress") && err == address.ErrCheckVersion { if !types.IsFork(height, "ForkMultiSignAddress") && err == address.ErrCheckVersion {
return nil return nil
} }
if !types.IsFork(height, "ForkBase58AddressCheck") && err == address.ErrAddressChecksum {
return nil
}
return err return err
} }
......
...@@ -222,7 +222,7 @@ ForkTxGroupPara= -1 ...@@ -222,7 +222,7 @@ ForkTxGroupPara= -1
ForkChainParamV2= -1 ForkChainParamV2= -1
ForkBlockCheck=1725000 ForkBlockCheck=1725000
ForkLocalDBAccess=1 ForkLocalDBAccess=1
ForkBase58AddressCheck=1800000
[fork.sub.coins] [fork.sub.coins]
Enable=0 Enable=0
......
...@@ -213,6 +213,8 @@ func SetTestNetFork() { ...@@ -213,6 +213,8 @@ func SetTestNetFork() {
systemFork.SetFork("chain33", "ForkBlockCheck", 1560000) systemFork.SetFork("chain33", "ForkBlockCheck", 1560000)
systemFork.SetFork("chain33", "ForkLocalDBAccess", 1572391) systemFork.SetFork("chain33", "ForkLocalDBAccess", 1572391)
systemFork.SetFork("chain33", "ForkTxGroupPara", 1687250) systemFork.SetFork("chain33", "ForkTxGroupPara", 1687250)
systemFork.SetFork("chain33", "ForkBase58AddressCheck", 1800000)
} }
func setLocalFork() { func setLocalFork() {
......
...@@ -58,6 +58,7 @@ message ReWriteRawTx { ...@@ -58,6 +58,7 @@ message ReWriteRawTx {
string to = 3; string to = 3;
string expire = 4; string expire = 4;
int64 fee = 5; int64 fee = 5;
int32 index = 6;
} }
message CreateTransactionGroup { message CreateTransactionGroup {
......
...@@ -174,6 +174,7 @@ ForkCheckBlockTime=1200000 ...@@ -174,6 +174,7 @@ ForkCheckBlockTime=1200000
ForkMultiSignAddress=1298600 ForkMultiSignAddress=1298600
ForkBlockCheck=1725000 ForkBlockCheck=1725000
ForkLocalDBAccess=1 ForkLocalDBAccess=1
ForkBase58AddressCheck=1800000
[fork.sub.coins] [fork.sub.coins]
Enable=0 Enable=0
......
...@@ -196,7 +196,7 @@ ForkCheckBlockTime=1200000 ...@@ -196,7 +196,7 @@ ForkCheckBlockTime=1200000
ForkMultiSignAddress=1298600 ForkMultiSignAddress=1298600
ForkBlockCheck=1 ForkBlockCheck=1
ForkLocalDBAccess=0 ForkLocalDBAccess=0
ForkBase58AddressCheck=1800000
[fork.sub.coins] [fork.sub.coins]
Enable=0 Enable=0
......
...@@ -438,6 +438,7 @@ type ReWriteRawTx struct { ...@@ -438,6 +438,7 @@ type ReWriteRawTx struct {
To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"` To string `protobuf:"bytes,3,opt,name=to,proto3" json:"to,omitempty"`
Expire string `protobuf:"bytes,4,opt,name=expire,proto3" json:"expire,omitempty"` Expire string `protobuf:"bytes,4,opt,name=expire,proto3" json:"expire,omitempty"`
Fee int64 `protobuf:"varint,5,opt,name=fee,proto3" json:"fee,omitempty"` Fee int64 `protobuf:"varint,5,opt,name=fee,proto3" json:"fee,omitempty"`
Index int32 `protobuf:"varint,6,opt,name=index,proto3" json:"index,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"` XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"` XXX_sizecache int32 `json:"-"`
...@@ -496,6 +497,13 @@ func (m *ReWriteRawTx) GetFee() int64 { ...@@ -496,6 +497,13 @@ func (m *ReWriteRawTx) GetFee() int64 {
return 0 return 0
} }
func (m *ReWriteRawTx) GetIndex() int32 {
if m != nil {
return m.Index
}
return 0
}
type CreateTransactionGroup struct { type CreateTransactionGroup struct {
Txs []string `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"` Txs []string `protobuf:"bytes,1,rep,name=txs,proto3" json:"txs,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"` XXX_NoUnkeyedLiteral struct{} `json:"-"`
...@@ -2049,88 +2057,88 @@ func init() { ...@@ -2049,88 +2057,88 @@ func init() {
func init() { proto.RegisterFile("transaction.proto", fileDescriptor_2cc4e03d2c28c490) } func init() { proto.RegisterFile("transaction.proto", fileDescriptor_2cc4e03d2c28c490) }
var fileDescriptor_2cc4e03d2c28c490 = []byte{ var fileDescriptor_2cc4e03d2c28c490 = []byte{
// 1320 bytes of a gzipped FileDescriptorProto // 1326 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xcf, 0x6e, 0x1b, 0xb7, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xc4, 0x57, 0xd1, 0x6e, 0x1b, 0xb7,
0x13, 0x86, 0xb4, 0x5a, 0x59, 0x1a, 0x29, 0xf9, 0xc5, 0x8b, 0x20, 0x11, 0x82, 0x5f, 0x13, 0x97, 0x12, 0x85, 0xb4, 0x5a, 0x5b, 0x1a, 0x29, 0xb9, 0xf1, 0xc2, 0x48, 0x84, 0xe0, 0xde, 0xc4, 0x97,
0x48, 0x81, 0x20, 0x08, 0x64, 0xc0, 0xce, 0xad, 0x05, 0xda, 0x24, 0x6e, 0x93, 0xc0, 0x49, 0x9a, 0x48, 0x81, 0x20, 0x08, 0x64, 0xc0, 0xce, 0x5b, 0x0b, 0xb4, 0x49, 0xdc, 0x26, 0x81, 0x93, 0x34,
0x32, 0xca, 0x1f, 0xb4, 0xbd, 0xd0, 0xab, 0xb1, 0xb4, 0x8d, 0xb4, 0x94, 0xb9, 0x94, 0xb3, 0x7a, 0x65, 0x94, 0xa4, 0x68, 0xfb, 0x42, 0xaf, 0xc6, 0xd2, 0x36, 0xd2, 0x52, 0xe6, 0x52, 0xce, 0xea,
0x81, 0x5e, 0xda, 0x5b, 0x1f, 0xa9, 0x2f, 0xd0, 0xc7, 0xe8, 0x63, 0x14, 0x1c, 0x92, 0xbb, 0xb4, 0x07, 0xfa, 0xd2, 0xbe, 0xf5, 0x93, 0xfa, 0x03, 0xfd, 0x8c, 0x7e, 0x46, 0xc1, 0x21, 0xb9, 0x4b,
0x25, 0x07, 0x39, 0x14, 0xe8, 0x8d, 0x1f, 0x39, 0x9a, 0xf9, 0x66, 0xe6, 0xe3, 0x2c, 0x05, 0xdb, 0x59, 0x72, 0x90, 0x87, 0x02, 0x7d, 0xe3, 0x21, 0x47, 0x33, 0x67, 0xce, 0x0c, 0x67, 0x29, 0xd8,
0x5a, 0x89, 0xbc, 0x10, 0xa9, 0xce, 0x64, 0x3e, 0x5c, 0x28, 0xa9, 0x65, 0x12, 0xeb, 0xd5, 0x02, 0xd1, 0x4a, 0xe4, 0x85, 0x48, 0x75, 0x26, 0xf3, 0xc1, 0x5c, 0x49, 0x2d, 0x93, 0x58, 0x2f, 0xe7,
0x8b, 0x1b, 0xfd, 0x54, 0xce, 0xe7, 0x7e, 0x93, 0x3d, 0x87, 0x4b, 0x0f, 0x8a, 0x02, 0x75, 0xf1, 0x58, 0xdc, 0xec, 0xa5, 0x72, 0x36, 0xf3, 0x9b, 0xec, 0x05, 0x5c, 0x79, 0x58, 0x14, 0xa8, 0x8b,
0x18, 0x73, 0x2c, 0xb2, 0x22, 0xb9, 0x06, 0x6d, 0x31, 0x97, 0xcb, 0x5c, 0x0f, 0x9a, 0x3b, 0x8d, 0x27, 0x98, 0x63, 0x91, 0x15, 0xc9, 0x75, 0xd8, 0x12, 0x33, 0xb9, 0xc8, 0x75, 0xbf, 0xb9, 0xd7,
0x3b, 0x11, 0x77, 0x28, 0xb9, 0x0d, 0x97, 0x14, 0xea, 0xa5, 0xca, 0x1f, 0x8c, 0xc7, 0x0a, 0x8b, 0xb8, 0x1b, 0x71, 0x87, 0x92, 0x3b, 0x70, 0x45, 0xa1, 0x5e, 0xa8, 0xfc, 0xe1, 0x68, 0xa4, 0xb0,
0x62, 0x10, 0xed, 0x34, 0xee, 0x74, 0xf9, 0xd9, 0x4d, 0xf6, 0x7b, 0x03, 0xae, 0x5a, 0x7f, 0x23, 0x28, 0xfa, 0xd1, 0x5e, 0xe3, 0x6e, 0x87, 0xaf, 0x6e, 0xb2, 0xdf, 0x1a, 0xb0, 0x6b, 0xfd, 0x0d,
0x13, 0xff, 0x18, 0xd5, 0x48, 0x7e, 0x5b, 0x62, 0x9a, 0xfc, 0x1f, 0xba, 0xa9, 0xcc, 0x72, 0x2d, 0x4d, 0xfc, 0x53, 0x54, 0x43, 0xf9, 0x75, 0x89, 0x69, 0xf2, 0x5f, 0xe8, 0xa4, 0x32, 0xcb, 0xb5,
0xdf, 0x63, 0x3e, 0x68, 0xd0, 0x4f, 0xeb, 0x8d, 0x0b, 0x83, 0x26, 0xd0, 0xca, 0xa5, 0x46, 0x8a, 0x7c, 0x8f, 0x79, 0xbf, 0x41, 0x3f, 0xad, 0x37, 0x2e, 0x0d, 0x9a, 0x40, 0x2b, 0x97, 0x1a, 0x29,
0xd5, 0xe7, 0xb4, 0x4e, 0x6e, 0x40, 0x07, 0x4b, 0x4c, 0x5f, 0x88, 0x39, 0x0e, 0x5a, 0xe4, 0xa8, 0x56, 0x8f, 0xd3, 0x3a, 0xb9, 0x09, 0x6d, 0x2c, 0x31, 0x7d, 0x29, 0x66, 0xd8, 0x6f, 0x91, 0xa3,
0xc2, 0xc9, 0x65, 0x68, 0x6a, 0x39, 0x88, 0x69, 0xb7, 0xa9, 0x25, 0xfb, 0xb5, 0x01, 0x97, 0x2d, 0x0a, 0x27, 0x57, 0xa1, 0xa9, 0x65, 0x3f, 0xa6, 0xdd, 0xa6, 0x96, 0xec, 0x97, 0x06, 0x5c, 0xb5,
0x9d, 0xb7, 0x99, 0x9e, 0x8e, 0x95, 0xf8, 0xf0, 0x1f, 0x11, 0xf9, 0xc5, 0xf3, 0xf0, 0x65, 0xf9, 0x74, 0xde, 0x65, 0x7a, 0x32, 0x52, 0xe2, 0xc3, 0xbf, 0x44, 0xe4, 0x67, 0xcf, 0xc3, 0xcb, 0xf2,
0x17, 0x79, 0xd8, 0x58, 0xad, 0x2a, 0xd6, 0x21, 0xc4, 0x14, 0xcb, 0x18, 0x1b, 0x42, 0xce, 0x3b, 0x0f, 0xf2, 0xb0, 0xb1, 0x5a, 0x55, 0xac, 0x63, 0x88, 0x29, 0x96, 0x31, 0x36, 0x84, 0x9c, 0x77,
0xad, 0x8d, 0xe3, 0x62, 0x35, 0x3f, 0x92, 0x33, 0x72, 0xdc, 0xe5, 0x0e, 0x05, 0x01, 0xa3, 0x30, 0x5a, 0x1b, 0xc7, 0xc5, 0x72, 0x76, 0x22, 0xa7, 0xe4, 0xb8, 0xc3, 0x1d, 0x0a, 0x02, 0x46, 0x61,
0x20, 0xfb, 0xbb, 0x01, 0x9d, 0x47, 0x0a, 0x85, 0xc6, 0x51, 0xe9, 0x22, 0x35, 0x7c, 0xa4, 0x0b, 0x40, 0xf6, 0x57, 0x03, 0xda, 0x8f, 0x15, 0x0a, 0x8d, 0xc3, 0xd2, 0x45, 0x6a, 0xf8, 0x48, 0x97,
0x59, 0x5e, 0x81, 0xe8, 0x18, 0xd1, 0x79, 0x32, 0xcb, 0x8a, 0x77, 0x2b, 0xe0, 0x7d, 0x13, 0x20, 0xb2, 0xbc, 0x06, 0xd1, 0x29, 0xa2, 0xf3, 0x64, 0x96, 0x15, 0xef, 0x56, 0xc0, 0xfb, 0x16, 0x40,
0xab, 0xfa, 0x42, 0xb5, 0xea, 0xf0, 0x60, 0x27, 0x19, 0xc0, 0x56, 0x56, 0x8c, 0xa8, 0x3e, 0x6d, 0x56, 0xd5, 0x85, 0xb4, 0x6a, 0xf3, 0x60, 0x27, 0xe9, 0xc3, 0x76, 0x56, 0x0c, 0x49, 0x9f, 0x2d,
0x3a, 0xf4, 0x30, 0xd9, 0x81, 0x1e, 0x95, 0xe9, 0x95, 0xcd, 0x64, 0x8b, 0x08, 0x85, 0x5b, 0x67, 0x3a, 0xf4, 0x30, 0xd9, 0x83, 0x2e, 0xc9, 0xf4, 0xda, 0x66, 0xb2, 0x4d, 0x84, 0xc2, 0xad, 0x95,
0x7a, 0xd3, 0x39, 0xd7, 0x9b, 0x6b, 0xd0, 0x36, 0x6b, 0x54, 0x83, 0xae, 0x2d, 0x81, 0x45, 0xec, 0xda, 0xb4, 0x2f, 0xd4, 0xe6, 0x3a, 0x6c, 0x99, 0x35, 0xaa, 0x7e, 0xc7, 0x4a, 0x60, 0x11, 0xcb,
0x1d, 0xf4, 0x39, 0xbe, 0x55, 0x99, 0x46, 0x2e, 0x3e, 0xb8, 0x6c, 0xcb, 0x2a, 0x5b, 0x9f, 0x7d, 0xa1, 0xc7, 0xf1, 0x9d, 0xca, 0x34, 0x72, 0xf1, 0xc1, 0x65, 0x5b, 0x56, 0xd9, 0xfa, 0xec, 0xa3,
0x14, 0x66, 0x8f, 0xe5, 0x22, 0x53, 0xbe, 0xfb, 0x0e, 0xf9, 0xec, 0xe3, 0x2a, 0x7b, 0x76, 0x17, 0x30, 0x7b, 0x2c, 0xe7, 0x99, 0xf2, 0xd5, 0x77, 0xc8, 0x67, 0x1f, 0xd7, 0xd9, 0xef, 0x42, 0x9c,
0xae, 0xb9, 0x1a, 0xd6, 0x97, 0xf2, 0xb1, 0x92, 0xcb, 0x85, 0xb1, 0xd5, 0x65, 0x31, 0x68, 0xec, 0xe5, 0x23, 0x2c, 0x29, 0x8f, 0x98, 0x5b, 0xc0, 0xee, 0xc1, 0x75, 0xa7, 0x6c, 0x7d, 0x55, 0x9f,
0x44, 0x77, 0xba, 0xdc, 0x2c, 0xd9, 0x4d, 0xe8, 0xbc, 0xce, 0x8b, 0x6c, 0x92, 0x8f, 0x4a, 0x53, 0x28, 0xb9, 0x98, 0x1b, 0x0f, 0xba, 0x2c, 0xfa, 0x8d, 0xbd, 0xe8, 0x6e, 0x87, 0x9b, 0x25, 0xbb,
0xb5, 0xb1, 0xd0, 0x82, 0x38, 0xf4, 0x39, 0xad, 0x99, 0x84, 0xde, 0x0b, 0xf9, 0x50, 0xcc, 0x44, 0x05, 0xed, 0x37, 0x79, 0x91, 0x8d, 0xf3, 0x61, 0x69, 0xb4, 0x1c, 0x09, 0x2d, 0x88, 0x59, 0x8f,
0x9e, 0x9a, 0x96, 0x5c, 0x85, 0x58, 0x97, 0x4f, 0xd0, 0xf3, 0xb4, 0xc0, 0x94, 0x6e, 0x21, 0x56, 0xd3, 0x9a, 0x49, 0xe8, 0xbe, 0x94, 0x8f, 0xc4, 0x54, 0xe4, 0xa9, 0x29, 0xd4, 0x2e, 0xc4, 0xba,
0xe6, 0x52, 0xba, 0x36, 0x7b, 0x48, 0x27, 0x2a, 0x3b, 0x7d, 0x8f, 0x2b, 0x97, 0x89, 0x87, 0x17, 0x7c, 0x8a, 0x9e, 0xbd, 0x05, 0x46, 0xd0, 0xb9, 0x58, 0x9a, 0xab, 0xea, 0x8a, 0xef, 0x21, 0x9d,
0xa5, 0xc3, 0x7e, 0x6b, 0x42, 0x2f, 0xe0, 0x1d, 0x94, 0xcf, 0xd2, 0x72, 0xc8, 0xc5, 0x9c, 0x49, 0xa8, 0xec, 0xfc, 0x3d, 0x2e, 0x5d, 0x7e, 0x1e, 0x5e, 0x96, 0x24, 0xfb, 0xb5, 0x09, 0xdd, 0x80,
0x31, 0xa6, 0x98, 0x7d, 0xee, 0x61, 0x32, 0x84, 0xae, 0x49, 0x48, 0xe8, 0xa5, 0xb2, 0xa2, 0xe8, 0x77, 0x20, 0xaa, 0xa5, 0xe5, 0x90, 0x8b, 0x39, 0x95, 0x62, 0x44, 0x31, 0x7b, 0xdc, 0xc3, 0x64,
0xed, 0x5d, 0x19, 0xd2, 0x30, 0x1a, 0xbe, 0xf2, 0xfb, 0xbc, 0x36, 0xf1, 0x05, 0x6c, 0xd5, 0xf2, 0x00, 0x1d, 0x93, 0x90, 0xd0, 0x0b, 0x65, 0x5b, 0xa5, 0x7b, 0x70, 0x6d, 0x40, 0x23, 0x6a, 0xf0,
0xa9, 0xb9, 0xd9, 0xaa, 0xfa, 0x52, 0x5f, 0x85, 0x38, 0x97, 0x79, 0x8a, 0x24, 0x90, 0x88, 0x5b, 0xda, 0xef, 0xf3, 0xda, 0xc4, 0xcb, 0xda, 0xaa, 0x65, 0xad, 0xb9, 0x59, 0xad, 0x7d, 0x01, 0x76,
0xe0, 0x1a, 0xb5, 0x55, 0x35, 0xea, 0x26, 0xc0, 0xc4, 0x54, 0xfb, 0x11, 0x49, 0xd5, 0xc8, 0x21, 0x21, 0xce, 0x65, 0x9e, 0x22, 0xc9, 0x1d, 0x71, 0x0b, 0x5c, 0xf9, 0xb6, 0xab, 0xf2, 0xdd, 0x02,
0xe6, 0xc1, 0x8e, 0xf1, 0x3e, 0x45, 0x31, 0x76, 0x82, 0xe8, 0x73, 0x87, 0x48, 0xb4, 0x58, 0xea, 0x18, 0x1b, 0xb5, 0x1f, 0x53, 0x03, 0xb7, 0xa9, 0x32, 0xc1, 0x8e, 0xf1, 0x3e, 0x41, 0x31, 0x72,
0x01, 0x38, 0xd1, 0x62, 0xa9, 0xd9, 0x7d, 0xe8, 0x07, 0xc5, 0x28, 0x92, 0xdb, 0x75, 0x03, 0x7b, 0x6d, 0xd2, 0xe3, 0x0e, 0x51, 0x2b, 0x63, 0xa9, 0xfb, 0xe0, 0x5a, 0x19, 0x4b, 0xcd, 0x1e, 0x40,
0x7b, 0x89, 0xcb, 0x2a, 0xb0, 0xb0, 0x4d, 0xfd, 0x1a, 0x2e, 0xf1, 0x2c, 0x9f, 0x54, 0xd9, 0x26, 0x2f, 0x10, 0xa3, 0x48, 0xee, 0xd4, 0x05, 0xec, 0x1e, 0x24, 0x2e, 0xab, 0xc0, 0xc2, 0x16, 0xf5,
0x43, 0x88, 0x33, 0x8d, 0x73, 0xff, 0xc3, 0x81, 0xfb, 0xe1, 0x19, 0xa3, 0xa7, 0x1a, 0xe7, 0xdc, 0x4b, 0xb8, 0xc2, 0xb3, 0x7c, 0x5c, 0x65, 0x9b, 0x0c, 0x20, 0xce, 0x34, 0xce, 0xfc, 0x0f, 0xfb,
0x9a, 0xb1, 0xa7, 0xb0, 0xbd, 0x76, 0x66, 0x78, 0x2f, 0x96, 0x47, 0xa6, 0x95, 0xc6, 0x4b, 0x9f, 0xee, 0x87, 0x2b, 0x46, 0xcf, 0x34, 0xce, 0xb8, 0x35, 0x63, 0xcf, 0x60, 0x67, 0xed, 0xcc, 0xf0,
0x3b, 0x64, 0x46, 0x4b, 0x5d, 0xef, 0x26, 0x1d, 0xd5, 0x1b, 0xec, 0x07, 0xe8, 0xd6, 0x3c, 0x4c, 0x9e, 0x2f, 0x4e, 0x4c, 0x29, 0x8d, 0x97, 0x1e, 0x77, 0xc8, 0x0c, 0x9c, 0x5a, 0xef, 0x26, 0x1d,
0xa9, 0x56, 0xd4, 0xc8, 0x98, 0x37, 0xf5, 0x2a, 0x70, 0x69, 0x7b, 0xb8, 0xd1, 0xa5, 0x1d, 0x3e, 0xd5, 0x1b, 0xec, 0x3b, 0xe8, 0xd4, 0x3c, 0x8c, 0x54, 0x4b, 0x2a, 0x64, 0xcc, 0x9b, 0x7a, 0x19,
0x81, 0xcb, 0x9f, 0xa1, 0x6f, 0xc4, 0xf5, 0xfd, 0x29, 0xaa, 0xd3, 0x0c, 0xe9, 0xe6, 0x2a, 0x4c, 0xb8, 0xb4, 0x35, 0xdc, 0xe8, 0xd2, 0x8e, 0xa4, 0xc0, 0xe5, 0x4f, 0xd0, 0x33, 0xcd, 0xf5, 0xed,
0xb3, 0x53, 0xa7, 0x91, 0x88, 0x7b, 0x68, 0x4e, 0x8e, 0xac, 0x76, 0xdd, 0xc8, 0xf0, 0xd0, 0x9c, 0x39, 0xaa, 0xf3, 0x0c, 0xe9, 0x3e, 0x2b, 0x4c, 0xb3, 0x73, 0xd7, 0x23, 0x11, 0xf7, 0xd0, 0x9c,
0xe8, 0xf2, 0x51, 0x30, 0x81, 0x3c, 0x64, 0x7f, 0x34, 0x60, 0x8b, 0xe3, 0x09, 0xc9, 0x37, 0x81, 0x9c, 0xd8, 0xde, 0x75, 0x83, 0xc4, 0x43, 0x73, 0xa2, 0xcb, 0xc7, 0xc1, 0x5c, 0xf2, 0x90, 0xfd,
0x96, 0x30, 0xaa, 0x76, 0x23, 0x4d, 0xb8, 0xbd, 0xe3, 0x99, 0x98, 0x90, 0xc3, 0x98, 0xd3, 0xda, 0xde, 0x80, 0x6d, 0x8e, 0x67, 0xd4, 0xbe, 0x09, 0xb4, 0x84, 0xe9, 0x6a, 0x37, 0xe8, 0x84, 0xdb,
0x08, 0x23, 0xad, 0x7c, 0xc5, 0xdc, 0x02, 0x93, 0xc5, 0x38, 0x53, 0x48, 0x8d, 0x21, 0x79, 0xc5, 0x3b, 0x9d, 0x8a, 0x31, 0x39, 0x8c, 0x39, 0xad, 0x4d, 0x63, 0xa4, 0x95, 0xaf, 0x98, 0x5b, 0x60,
0xbc, 0xde, 0xb0, 0x32, 0xc8, 0x26, 0x53, 0xed, 0x45, 0x66, 0x91, 0xf1, 0x95, 0xe5, 0x63, 0x2c, 0xb2, 0x18, 0x65, 0x0a, 0xa9, 0x30, 0xd4, 0x5e, 0x31, 0xaf, 0x37, 0x6c, 0x1b, 0x64, 0xe3, 0x89,
0xbd, 0xc8, 0x08, 0xb0, 0x77, 0x00, 0x1c, 0x4f, 0x5e, 0xaa, 0xec, 0x54, 0xa4, 0xab, 0x3a, 0x5e, 0xf6, 0x4d, 0x66, 0xd1, 0xea, 0x9d, 0x8e, 0xfc, 0x9d, 0xfe, 0x1e, 0x80, 0xe3, 0xd9, 0x2b, 0x95,
0xe3, 0xc2, 0x78, 0xcd, 0x8b, 0xe3, 0x45, 0x61, 0x3c, 0x76, 0x1d, 0xe2, 0x27, 0x58, 0xae, 0x0f, 0x9d, 0x8b, 0x74, 0x59, 0xc7, 0x6b, 0x5c, 0x1a, 0xaf, 0x79, 0x79, 0xbc, 0x28, 0x8c, 0xc7, 0x6e,
0x20, 0xb6, 0x84, 0x1e, 0xc7, 0xc5, 0x6c, 0x35, 0x2a, 0x9f, 0xe6, 0xc7, 0xd2, 0xe4, 0x3d, 0x15, 0x40, 0xfc, 0x14, 0xcb, 0xf5, 0xb1, 0xc4, 0x16, 0xd0, 0xe5, 0x38, 0x9f, 0x2e, 0x87, 0xe5, 0xb3,
0xc5, 0xd4, 0x4f, 0x07, 0xb3, 0x0e, 0x7c, 0x36, 0x37, 0xe7, 0x10, 0x05, 0x39, 0x24, 0xb7, 0xa1, 0xfc, 0x54, 0x9a, 0xbc, 0x27, 0xa2, 0x98, 0xf8, 0xe9, 0x60, 0xd6, 0x81, 0xcf, 0xe6, 0xe6, 0x1c,
0x2d, 0xe8, 0xab, 0x34, 0x68, 0x91, 0x0c, 0xfb, 0x4e, 0x86, 0xf4, 0xf9, 0xe0, 0xee, 0x8c, 0x7d, 0xa2, 0x20, 0x87, 0xe4, 0x0e, 0x6c, 0x09, 0xfa, 0x56, 0xf5, 0x5b, 0xd4, 0x86, 0x3d, 0xd7, 0x86,
0x0e, 0x5d, 0x8e, 0x27, 0xa3, 0xf2, 0x59, 0x56, 0xe8, 0xb3, 0x89, 0x46, 0x2e, 0x51, 0xb6, 0x5f, 0xf4, 0x51, 0xe1, 0xee, 0x8c, 0xfd, 0x1f, 0x3a, 0x1c, 0xcf, 0x86, 0xe5, 0xf3, 0xac, 0xd0, 0xab,
0x31, 0x23, 0xa3, 0x4f, 0xbb, 0x14, 0x43, 0xb8, 0x4c, 0x3f, 0x7a, 0xa9, 0xe4, 0x02, 0xd5, 0x77, 0x89, 0x46, 0x2e, 0x51, 0x76, 0x58, 0x31, 0x23, 0xa3, 0x4f, 0xbb, 0x14, 0x03, 0xb8, 0x4a, 0x3f,
0x88, 0xa6, 0x5e, 0x0b, 0x0f, 0x5c, 0x80, 0x7a, 0x83, 0x71, 0x80, 0x51, 0xf9, 0x44, 0x14, 0x53, 0x7a, 0xa5, 0xe4, 0x1c, 0xd5, 0x37, 0x88, 0x46, 0xaf, 0xb9, 0x07, 0x2e, 0x40, 0xbd, 0xc1, 0x38,
0x8a, 0x61, 0x32, 0x15, 0xc5, 0x14, 0x0b, 0x2f, 0x7e, 0x8b, 0x6a, 0x82, 0xcd, 0x80, 0x60, 0x30, 0xc0, 0xb0, 0x7c, 0x2a, 0x8a, 0x09, 0xc5, 0x30, 0x99, 0x8a, 0x62, 0x82, 0x85, 0x6f, 0x7e, 0x8b,
0x40, 0xa2, 0x9d, 0xa8, 0x1e, 0x20, 0xec, 0x2b, 0x33, 0xf3, 0xab, 0x92, 0x16, 0xc9, 0x3d, 0xa3, 0x6a, 0x82, 0xcd, 0x80, 0x60, 0x30, 0x40, 0xa2, 0xbd, 0xa8, 0x1e, 0x20, 0xec, 0x0b, 0xf3, 0x25,
0x42, 0x5a, 0x9e, 0x63, 0x1f, 0x58, 0x71, 0x6f, 0xc2, 0x86, 0x46, 0x03, 0x29, 0x66, 0x0b, 0xfd, 0xa8, 0x24, 0x2d, 0x92, 0xfb, 0xa6, 0x0b, 0x69, 0x79, 0x81, 0x7d, 0x60, 0xc5, 0xbd, 0x09, 0x1b,
0x4c, 0x4e, 0xd6, 0xee, 0xd2, 0x15, 0x88, 0x66, 0x72, 0xe2, 0x2e, 0x92, 0x59, 0x32, 0x61, 0x84, 0x98, 0x1e, 0x48, 0x31, 0x9b, 0xeb, 0xe7, 0x72, 0xbc, 0x76, 0x97, 0xae, 0x41, 0x34, 0x95, 0x63,
0x4c, 0xf6, 0x6b, 0xc6, 0xb7, 0xa0, 0x79, 0xf8, 0x86, 0x2e, 0x6b, 0x6f, 0xef, 0x7f, 0x2e, 0xe6, 0x77, 0x91, 0xcc, 0x92, 0x09, 0xd3, 0xc8, 0x64, 0xbf, 0x66, 0x7c, 0x1b, 0x9a, 0xc7, 0x6f, 0xe9,
0x21, 0xae, 0xde, 0x88, 0xd9, 0x12, 0x79, 0xf3, 0xf0, 0x4d, 0xf2, 0x05, 0xb4, 0x66, 0x72, 0x52, 0xb2, 0x76, 0x0f, 0xfe, 0xe3, 0x62, 0x1e, 0xe3, 0xf2, 0xad, 0x98, 0x2e, 0x90, 0x37, 0x8f, 0xdf,
0x10, 0xff, 0xde, 0xde, 0x76, 0x45, 0xcb, 0x87, 0xe7, 0x74, 0xcc, 0x0e, 0x4c, 0x27, 0x68, 0xef, 0x26, 0x9f, 0x41, 0x6b, 0x2a, 0xc7, 0x05, 0xf1, 0xef, 0x1e, 0xec, 0x54, 0xb4, 0x7c, 0x78, 0x4e,
0x40, 0x68, 0xb1, 0x16, 0xe6, 0x13, 0xbd, 0xfc, 0xd5, 0x80, 0xce, 0xa8, 0xe4, 0x58, 0x2c, 0x67, 0xc7, 0xec, 0xc8, 0x54, 0x82, 0xf6, 0x8e, 0x84, 0x16, 0x6b, 0x61, 0x3e, 0xd1, 0xcb, 0x9f, 0x0d,
0x3a, 0xd0, 0x54, 0x63, 0xb3, 0xa6, 0xac, 0xb2, 0x9d, 0xa6, 0x18, 0x89, 0xd6, 0x4e, 0xf9, 0x4d, 0x68, 0x0f, 0x4b, 0x8e, 0xc5, 0x62, 0xaa, 0x83, 0x9e, 0x6a, 0x6c, 0xee, 0xa9, 0x66, 0xf0, 0xad,
0xad, 0x37, 0x5f, 0xd2, 0xfb, 0xd0, 0x53, 0x36, 0xe4, 0x58, 0xb8, 0x47, 0x41, 0x58, 0xe9, 0x8a, 0x4b, 0x18, 0x35, 0xad, 0x9d, 0xf2, 0x9b, 0x4a, 0x6f, 0xbe, 0xaf, 0x0f, 0xa0, 0xab, 0x6c, 0xc8,
0x3e, 0x0f, 0xcd, 0x8c, 0x3a, 0x8e, 0x66, 0x32, 0x7d, 0xaf, 0xb3, 0xb9, 0xff, 0x0e, 0xd4, 0x1b, 0x91, 0x70, 0x4f, 0x85, 0x50, 0xe9, 0x8a, 0x3e, 0x0f, 0xcd, 0x4c, 0x77, 0x9c, 0x4c, 0x65, 0xfa,
0x66, 0xc8, 0xdb, 0x08, 0xf4, 0xcd, 0x6f, 0xd3, 0xa5, 0x09, 0x76, 0xd8, 0x9f, 0x4d, 0xd8, 0x0e, 0x5e, 0x67, 0x33, 0xff, 0x1d, 0xa8, 0x37, 0xcc, 0x90, 0xb7, 0x11, 0xe8, 0x25, 0xb0, 0x45, 0x97,
0x78, 0x1c, 0xa0, 0x16, 0xd9, 0xcc, 0xb1, 0x6d, 0x7c, 0x94, 0xed, 0x3d, 0x9a, 0x66, 0x86, 0x06, 0x26, 0xd8, 0x61, 0x7f, 0x34, 0x61, 0x27, 0xe0, 0x71, 0x84, 0x5a, 0x64, 0x53, 0xc7, 0xb6, 0xf1,
0x65, 0xba, 0x99, 0xa9, 0x37, 0xa1, 0x09, 0xaa, 0xa4, 0x3c, 0xb6, 0x35, 0x36, 0x13, 0x94, 0x50, 0x51, 0xb6, 0xf7, 0x69, 0x9a, 0x19, 0x1a, 0x94, 0xe9, 0x66, 0xa6, 0xde, 0x84, 0x26, 0xa8, 0x92,
0x50, 0xc5, 0xd6, 0xe6, 0x2a, 0xc6, 0xe1, 0xcd, 0x3c, 0x93, 0x6b, 0xfb, 0x7c, 0xae, 0xf5, 0xbb, 0xf2, 0xd4, 0x6a, 0x6c, 0x26, 0x28, 0xa1, 0x40, 0xc5, 0xd6, 0x66, 0x15, 0xe3, 0xf0, 0x66, 0xae,
0x6b, 0xeb, 0xcc, 0xbb, 0xeb, 0x06, 0x74, 0x8e, 0x95, 0x9c, 0xd3, 0x84, 0x74, 0xaf, 0x1e, 0x8f, 0xe4, 0xba, 0x75, 0x31, 0xd7, 0xfa, 0x35, 0xb6, 0xbd, 0xf2, 0x1a, 0xbb, 0x09, 0xed, 0x53, 0x25,
0xcf, 0xd5, 0xa7, 0x7b, 0xbe, 0x3e, 0xc1, 0x2c, 0x80, 0x8f, 0xcc, 0x82, 0x6f, 0x20, 0x59, 0x2b, 0x67, 0x34, 0x21, 0xdd, 0x5b, 0xc8, 0xe3, 0x0b, 0xfa, 0x74, 0x2e, 0xea, 0x13, 0xcc, 0x02, 0xf8,
0x62, 0x91, 0xdc, 0x0d, 0xef, 0xfb, 0x60, 0xbd, 0x8c, 0xd6, 0xce, 0xde, 0xfa, 0x1d, 0xe8, 0xb8, 0xc8, 0x2c, 0xf8, 0x0a, 0x92, 0x35, 0x11, 0x8b, 0xe4, 0x5e, 0x78, 0xdf, 0xfb, 0xeb, 0x32, 0x5a,
0x61, 0x4e, 0x77, 0xd5, 0x70, 0xf3, 0xef, 0x1f, 0x0b, 0xd8, 0x2e, 0x5c, 0xe7, 0x78, 0x72, 0x80, 0x3b, 0x7b, 0xeb, 0xf7, 0xa0, 0xed, 0x86, 0x39, 0xdd, 0x55, 0xc3, 0xcd, 0xbf, 0x7f, 0x2c, 0x60,
0xa9, 0x1c, 0xd3, 0x4b, 0x2c, 0x78, 0x7b, 0x6c, 0x7c, 0xed, 0xb0, 0x2f, 0xa1, 0xfb, 0xba, 0x40, 0xfb, 0x70, 0x83, 0xe3, 0xd9, 0x11, 0xa6, 0x72, 0x44, 0xef, 0xb3, 0xe0, 0xed, 0xb1, 0xf1, 0xb5,
0x45, 0x4f, 0x37, 0x32, 0x91, 0x8b, 0x2c, 0xad, 0x4c, 0x0c, 0x30, 0x5f, 0x97, 0x54, 0xe6, 0x1a, 0xc3, 0x3e, 0x87, 0xce, 0x9b, 0x02, 0x15, 0x3d, 0xe8, 0xc8, 0x44, 0xce, 0xb3, 0xb4, 0x32, 0x31,
0xdd, 0x5c, 0xe8, 0x72, 0x0f, 0xd9, 0x4f, 0xd0, 0x7b, 0xbd, 0x98, 0x28, 0x31, 0xc6, 0xe7, 0xa8, 0xc0, 0x7c, 0x5d, 0x52, 0x99, 0x6b, 0x74, 0x73, 0xa1, 0xc3, 0x3d, 0x64, 0x3f, 0x42, 0xf7, 0xcd,
0x85, 0x29, 0x61, 0xa1, 0x85, 0xd2, 0x59, 0x3e, 0x21, 0x0f, 0x1d, 0x5e, 0x61, 0xe3, 0xe4, 0x14, 0x7c, 0xac, 0xc4, 0x08, 0x5f, 0xa0, 0x16, 0x46, 0xc2, 0x42, 0x0b, 0xa5, 0xb3, 0x7c, 0x4c, 0x1e,
0x55, 0xe1, 0x87, 0x79, 0x97, 0x7b, 0x78, 0xd1, 0x28, 0x7f, 0x78, 0xeb, 0xc7, 0xcf, 0x26, 0x99, 0xda, 0xbc, 0xc2, 0xc6, 0xc9, 0x39, 0xaa, 0xc2, 0x0f, 0xf3, 0x0e, 0xf7, 0xf0, 0xb2, 0x51, 0xfe,
0x9e, 0x2e, 0x8f, 0x86, 0xa9, 0x9c, 0xef, 0xee, 0xef, 0xa7, 0xf9, 0x6e, 0x3a, 0x15, 0x59, 0xbe, 0xe8, 0xf6, 0x0f, 0xff, 0x1b, 0x67, 0x7a, 0xb2, 0x38, 0x19, 0xa4, 0x72, 0xb6, 0x7f, 0x78, 0x98,
0xbf, 0xbf, 0x4b, 0x45, 0x3a, 0x6a, 0xd3, 0xbf, 0xb0, 0xfd, 0x7f, 0x02, 0x00, 0x00, 0xff, 0xff, 0xe6, 0xfb, 0xe9, 0x44, 0x64, 0xf9, 0xe1, 0xe1, 0x3e, 0x89, 0x74, 0xb2, 0x45, 0xff, 0xcd, 0x0e,
0xba, 0x68, 0x0f, 0x9b, 0xaf, 0x0d, 0x00, 0x00, 0xff, 0x0e, 0x00, 0x00, 0xff, 0xff, 0x05, 0xe5, 0x01, 0x1a, 0xc5, 0x0d, 0x00, 0x00,
} }
...@@ -137,6 +137,30 @@ func (txgroup *Transactions) CheckSign() bool { ...@@ -137,6 +137,30 @@ func (txgroup *Transactions) CheckSign() bool {
return true return true
} }
//RebuiltGroup 交易内容有变化时需要重新构建交易组
func (txgroup *Transactions) RebuiltGroup() {
header := txgroup.Txs[0].Hash()
for i := len(txgroup.Txs) - 1; i >= 0; i-- {
txgroup.Txs[i].Header = header
if i == 0 {
header = txgroup.Txs[0].Hash()
} else {
txgroup.Txs[i-1].Next = txgroup.Txs[i].Hash()
}
}
for i := 0; i < len(txgroup.Txs); i++ {
txgroup.Txs[i].Header = header
}
}
//SetExpire 设置交易组中交易的过期时间
func (txgroup *Transactions) SetExpire(n int, expire time.Duration) {
if n >= len(txgroup.GetTxs()) {
return
}
txgroup.GetTxs()[n].SetExpire(expire)
}
//IsExpire 交易是否过期 //IsExpire 交易是否过期
func (txgroup *Transactions) IsExpire(height, blocktime int64) bool { func (txgroup *Transactions) IsExpire(height, blocktime int64) bool {
txs := txgroup.Txs txs := txgroup.Txs
......
...@@ -7,6 +7,7 @@ package types ...@@ -7,6 +7,7 @@ package types
import ( import (
"encoding/hex" "encoding/hex"
"testing" "testing"
"time"
"github.com/33cn/chain33/common" "github.com/33cn/chain33/common"
"github.com/33cn/chain33/common/crypto" "github.com/33cn/chain33/common/crypto"
...@@ -274,3 +275,40 @@ func BenchmarkHash(b *testing.B) { ...@@ -274,3 +275,40 @@ func BenchmarkHash(b *testing.B) {
tx.Hash() tx.Hash()
} }
} }
func TestSetGroupExpire(t *testing.T) {
rawtx := "0a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6720c0843d30aab4d59684b5cce7143a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4ab50c0aa3010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6720c0843d30aab4d59684b5cce7143a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522008217c413b035fddd8f34a303e90a29e661746ed9b23a97768c1f25817c2c3450a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a673094fbcabe96c99ea7163a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f552203c6a2b11cce466891f084b49450472b1d4c39213f63117d3d4ce2a3851304ebc0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730c187fb80fe88ce9e3c3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522066419d70492f757d7285fd226dff62da8d803c8121ded95242d222dbb10f2d9b0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a673098aa929ab292b3f0023a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f552202bab08051d24fe923f66c8aeea4ce3f425d47a72f7c5c230a2b1427e04e2eb510a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730bfe9abb3edc6d9cb163a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f55220e1ba0493aa431ea3071026bd8dfa8280efab53ce86441fc474a1c19550a554ba0a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730d2e196a8ecada9d53e3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522016600fbfa23b3f0e8f9a14b716ce8f4064c091fbf6fa94489bc9d14b5b6049a60a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730a0b7b1b1dda2f4c5743a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522089d0442d76713369022499d054db65ccacbf5c627a525bd5454e0a30d23fa2990a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730c5838f94e2f49acb4b3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522018f208938606b390d752898332a84a9fbb900c2ed55ec33cd54d09b1970043b90a9f010a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a67308dfddb82faf7dfc4113a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522013002bab7a9c65881bd937a6fded4c3959bb631fa84434572970c1ec3e6fccf90a7d0a0a757365722e7772697465121d236d642368616b6468676f7177656a6872676f716a676f6a71776c6a6730b8b082d799a4ddc93a3a2231444e615344524739524431397335396d65416f654e34613246365248393766536f400a4a201f533ac07c3fc4c716f65cdb0f1f02e7f5371b5164277210dafb1dbdd4a5f4f5522008217c413b035fddd8f34a303e90a29e661746ed9b23a97768c1f25817c2c345"
var tx Transaction
txhex, _ := hex.DecodeString(rawtx)
Decode(txhex, &tx)
group, err := tx.GetTxGroup()
if err != nil {
t.Error(err)
return
}
for _, tmptx := range group.GetTxs() {
if tmptx.GetExpire() != 0 {
t.Error("TestSetGroupExpire Expire !=0", "tx", tmptx)
}
}
//设置交易组过期时间
for i := 0; i < len(group.Txs); i++ {
group.SetExpire(i, time.Duration(120))
}
group.RebuiltGroup()
//校验重组后的交易组
firsttxhash := group.GetTxs()[0].Hash()
for _, tmptx := range group.GetTxs() {
if string(tmptx.GetHeader()) != string(firsttxhash) {
t.Error("TestSetGroupExpire group: tx.Hash != group.Txs[0].Hash()")
}
}
for _, tmptx := range group.GetTxs() {
if tmptx.GetExpire() == 0 {
t.Error("TestSetGroupExpire Expire == 0", "tx", tmptx)
}
}
}
...@@ -977,8 +977,8 @@ func (wallet *Wallet) ProcWalletAddBlock(block *types.BlockDetail) { ...@@ -977,8 +977,8 @@ func (wallet *Wallet) ProcWalletAddBlock(block *types.BlockDetail) {
walletlog.Debug("ProcWalletAddBlock", "fromaddress", fromaddress) walletlog.Debug("ProcWalletAddBlock", "fromaddress", fromaddress)
continue continue
} }
//toaddr //toaddr获取交易中真实的接收地址,主要是针对para
toaddr := tx.GetTo() toaddr := tx.GetRealToAddr()
if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) { if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) {
param.sendRecvFlag = recvTx param.sendRecvFlag = recvTx
wallet.buildAndStoreWalletTxDetail(param) wallet.buildAndStoreWalletTxDetail(param)
...@@ -1082,7 +1082,7 @@ func (wallet *Wallet) ProcWalletDelBlock(block *types.BlockDetail) { ...@@ -1082,7 +1082,7 @@ func (wallet *Wallet) ProcWalletDelBlock(block *types.BlockDetail) {
continue continue
} }
//toaddr //toaddr
toaddr := tx.GetTo() toaddr := tx.GetRealToAddr()
if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) { if len(toaddr) != 0 && wallet.AddrInWallet(toaddr) {
newbatch.Delete(wcom.CalcTxKey(heightstr)) newbatch.Delete(wcom.CalcTxKey(heightstr))
} }
...@@ -1246,7 +1246,7 @@ func (wallet *Wallet) saveSeed(password string, seed string) (bool, error) { ...@@ -1246,7 +1246,7 @@ func (wallet *Wallet) saveSeed(password string, seed string) (bool, error) {
return false, err return false, err
} }
ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), seed, password, newBatch) ok, err := SaveSeedInBatch(wallet.walletStore.GetDB(), newseed, password, newBatch)
if !ok { if !ok {
walletlog.Error("saveSeed", "SaveSeed err", err) walletlog.Error("saveSeed", "SaveSeed err", err)
return false, err return false, err
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment