swarm: Merge branch 'master' into bzz-hash-scheme

Fixed conflicts with other bzz schemes in code.
This commit is contained in:
Janos Guljas 2017-12-19 17:32:19 +01:00
commit bac384dadc
28 changed files with 379 additions and 131 deletions

View file

@ -58,6 +58,9 @@ func decryptPreSaleKey(fileContent []byte, password string) (key *Key, err error
if err != nil { if err != nil {
return nil, errors.New("invalid hex in encSeed") return nil, errors.New("invalid hex in encSeed")
} }
if len(encSeedBytes) < 16 {
return nil, errors.New("invalid encSeed, too short")
}
iv := encSeedBytes[:16] iv := encSeedBytes[:16]
cipherText := encSeedBytes[16:] cipherText := encSeedBytes[16:]
/* /*

View file

@ -120,8 +120,12 @@ func remoteConsole(ctx *cli.Context) error {
if ctx.GlobalIsSet(utils.DataDirFlag.Name) { if ctx.GlobalIsSet(utils.DataDirFlag.Name) {
path = ctx.GlobalString(utils.DataDirFlag.Name) path = ctx.GlobalString(utils.DataDirFlag.Name)
} }
if path != "" && ctx.GlobalBool(utils.TestnetFlag.Name) { if path != "" {
path = filepath.Join(path, "testnet") if ctx.GlobalBool(utils.TestnetFlag.Name) {
path = filepath.Join(path, "testnet")
} else if ctx.GlobalBool(utils.RinkebyFlag.Name) {
path = filepath.Join(path, "rinkeby")
}
} }
endpoint = fmt.Sprintf("%s/geth.ipc", path) endpoint = fmt.Sprintf("%s/geth.ipc", path)
} }

View file

@ -36,9 +36,10 @@ import (
// Ethash proof-of-work protocol constants. // Ethash proof-of-work protocol constants.
var ( var (
FrontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block FrontierBlockReward *big.Int = big.NewInt(5e+18) // Block reward in wei for successfully mining a block
ByzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium ByzantiumBlockReward *big.Int = big.NewInt(3e+18) // Block reward in wei for successfully mining a block upward from Byzantium
maxUncles = 2 // Maximum number of uncles allowed in a single block maxUncles = 2 // Maximum number of uncles allowed in a single block
allowedFutureBlockTime = 15 * time.Second // Max time from current time allowed for blocks, before they're considered future blocks
) )
// Various error messages to mark blocks invalid. These should be private to // Various error messages to mark blocks invalid. These should be private to
@ -231,7 +232,7 @@ func (ethash *Ethash) verifyHeader(chain consensus.ChainReader, header, parent *
return errLargeBlockTime return errLargeBlockTime
} }
} else { } else {
if header.Time.Cmp(big.NewInt(time.Now().Unix())) > 0 { if header.Time.Cmp(big.NewInt(time.Now().Add(allowedFutureBlockTime).Unix())) > 0 {
return consensus.ErrFutureBlock return consensus.ErrFutureBlock
} }
} }

View file

@ -92,6 +92,9 @@ func New(config Config) (*Console, error) {
printer: config.Printer, printer: config.Printer,
histPath: filepath.Join(config.DataDir, HistoryFile), histPath: filepath.Join(config.DataDir, HistoryFile),
} }
if err := os.MkdirAll(config.DataDir, 0700); err != nil {
return nil, err
}
if err := console.init(config.Preload); err != nil { if err := console.init(config.Preload); err != nil {
return nil, err return nil, err
} }
@ -423,7 +426,7 @@ func (c *Console) Execute(path string) error {
return c.jsre.Exec(path) return c.jsre.Exec(path)
} }
// Stop cleans up the console and terminates the runtime envorinment. // Stop cleans up the console and terminates the runtime environment.
func (c *Console) Stop(graceful bool) error { func (c *Console) Stop(graceful bool) error {
if err := ioutil.WriteFile(c.histPath, []byte(strings.Join(c.history, "\n")), 0600); err != nil { if err := ioutil.WriteFile(c.histPath, []byte(strings.Join(c.history, "\n")), 0600); err != nil {
return err return err

View file

@ -137,7 +137,7 @@ func (r *ReleaseService) checkVersion() {
if err != nil { if err != nil {
if err == bind.ErrNoCode { if err == bind.ErrNoCode {
log.Debug("Release oracle not found", "contract", r.config.Oracle) log.Debug("Release oracle not found", "contract", r.config.Oracle)
} else { } else if err != les.ErrNoPeers {
log.Error("Failed to retrieve current release", "err", err) log.Error("Failed to retrieve current release", "err", err)
} }
return return

View file

@ -38,7 +38,7 @@ type (
) )
// run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter. // run runs the given contract and takes care of running precompiles with a fallback to the byte code interpreter.
func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, error) { func run(evm *EVM, contract *Contract, input []byte) ([]byte, error) {
if contract.CodeAddr != nil { if contract.CodeAddr != nil {
precompiles := PrecompiledContractsHomestead precompiles := PrecompiledContractsHomestead
if evm.ChainConfig().IsByzantium(evm.BlockNumber) { if evm.ChainConfig().IsByzantium(evm.BlockNumber) {
@ -48,7 +48,7 @@ func run(evm *EVM, snapshot int, contract *Contract, input []byte) ([]byte, erro
return RunPrecompiledContract(p, input, contract) return RunPrecompiledContract(p, input, contract)
} }
} }
return evm.interpreter.Run(snapshot, contract, input) return evm.interpreter.Run(contract, input)
} }
// Context provides the EVM with auxiliary information. Once provided // Context provides the EVM with auxiliary information. Once provided
@ -171,7 +171,7 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
ret, err = run(evm, snapshot, contract, input) ret, err = run(evm, contract, input)
// When an error was returned by the EVM or when setting the creation code // When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally // above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in homestead this also counts for code storage gas errors. // when we're in homestead this also counts for code storage gas errors.
@ -215,7 +215,7 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
contract := NewContract(caller, to, value, gas) contract := NewContract(caller, to, value, gas)
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
ret, err = run(evm, snapshot, contract, input) ret, err = run(evm, contract, input)
if err != nil { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted { if err != errExecutionReverted {
@ -248,7 +248,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
contract := NewContract(caller, to, nil, gas).AsDelegate() contract := NewContract(caller, to, nil, gas).AsDelegate()
contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr)) contract.SetCallCode(&addr, evm.StateDB.GetCodeHash(addr), evm.StateDB.GetCode(addr))
ret, err = run(evm, snapshot, contract, input) ret, err = run(evm, contract, input)
if err != nil { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted { if err != errExecutionReverted {
@ -291,7 +291,7 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// When an error was returned by the EVM or when setting the creation code // When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally // above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors. // when we're in Homestead this also counts for code storage gas errors.
ret, err = run(evm, snapshot, contract, input) ret, err = run(evm, contract, input)
if err != nil { if err != nil {
evm.StateDB.RevertToSnapshot(snapshot) evm.StateDB.RevertToSnapshot(snapshot)
if err != errExecutionReverted { if err != errExecutionReverted {
@ -338,7 +338,7 @@ func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.I
if evm.vmConfig.NoRecursion && evm.depth > 0 { if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, contractAddr, gas, nil return nil, contractAddr, gas, nil
} }
ret, err = run(evm, snapshot, contract, nil) ret, err = run(evm, contract, nil)
// check whether the max code size has been exceeded // check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned // if the contract creation ran successfully and no errors were returned

View file

@ -107,9 +107,9 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
// the return byte-slice and an error if one occurred. // the return byte-slice and an error if one occurred.
// //
// It's important to note that any errors returned by the interpreter should be // It's important to note that any errors returned by the interpreter should be
// considered a revert-and-consume-all-gas operation. No error specific checks // considered a revert-and-consume-all-gas operation except for
// should be handled to reduce complexity and errors further down the in. // errExecutionReverted which means revert-and-keep-gas-left.
func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret []byte, err error) { func (in *Interpreter) Run(contract *Contract, input []byte) (ret []byte, err error) {
// Increment the call depth which is restricted to 1024 // Increment the call depth which is restricted to 1024
in.evm.depth++ in.evm.depth++
defer func() { in.evm.depth-- }() defer func() { in.evm.depth-- }()

View file

@ -79,7 +79,7 @@ func ToECDSA(d []byte) (*ecdsa.PrivateKey, error) {
return toECDSA(d, true) return toECDSA(d, true)
} }
// ToECDSAUnsafe blidly converts a binary blob to a private key. It should almost // ToECDSAUnsafe blindly converts a binary blob to a private key. It should almost
// never be used unless you are sure the input is valid and want to avoid hitting // never be used unless you are sure the input is valid and want to avoid hitting
// errors due to bad origin encoding (0 prefixes cut off). // errors due to bad origin encoding (0 prefixes cut off).
func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey { func ToECDSAUnsafe(d []byte) *ecdsa.PrivateKey {

View file

@ -34,7 +34,6 @@ package secp256k1
import ( import (
"crypto/elliptic" "crypto/elliptic"
"math/big" "math/big"
"sync"
"unsafe" "unsafe"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
@ -42,7 +41,7 @@ import (
/* /*
#include "libsecp256k1/include/secp256k1.h" #include "libsecp256k1/include/secp256k1.h"
extern int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar); extern int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, const unsigned char *point, const unsigned char *scalar);
*/ */
import "C" import "C"
@ -236,7 +235,7 @@ func (BitCurve *BitCurve) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int,
math.ReadBits(By, point[32:]) math.ReadBits(By, point[32:])
pointPtr := (*C.uchar)(unsafe.Pointer(&point[0])) pointPtr := (*C.uchar)(unsafe.Pointer(&point[0]))
scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0])) scalarPtr := (*C.uchar)(unsafe.Pointer(&scalar[0]))
res := C.secp256k1_pubkey_scalar_mul(context, pointPtr, scalarPtr) res := C.secp256k1_ext_scalar_mul(context, pointPtr, scalarPtr)
// Unpack the result and clear temporaries. // Unpack the result and clear temporaries.
x := new(big.Int).SetBytes(point[:32]) x := new(big.Int).SetBytes(point[:32])
@ -263,14 +262,10 @@ func (BitCurve *BitCurve) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
// X9.62. // X9.62.
func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte { func (BitCurve *BitCurve) Marshal(x, y *big.Int) []byte {
byteLen := (BitCurve.BitSize + 7) >> 3 byteLen := (BitCurve.BitSize + 7) >> 3
ret := make([]byte, 1+2*byteLen) ret := make([]byte, 1+2*byteLen)
ret[0] = 4 // uncompressed point ret[0] = 4 // uncompressed point flag
math.ReadBits(x, ret[1:1+byteLen])
xBytes := x.Bytes() math.ReadBits(y, ret[1+byteLen:])
copy(ret[1+byteLen-len(xBytes):], xBytes)
yBytes := y.Bytes()
copy(ret[1+2*byteLen-len(yBytes):], yBytes)
return ret return ret
} }
@ -289,24 +284,21 @@ func (BitCurve *BitCurve) Unmarshal(data []byte) (x, y *big.Int) {
return return
} }
var ( var theCurve = new(BitCurve)
initonce sync.Once
theCurve *BitCurve
)
// S256 returns a BitCurve which implements secp256k1 (see SEC 2 section 2.7.1) func init() {
// See SEC 2 section 2.7.1
// curve parameters taken from:
// http://www.secg.org/collateral/sec2_final.pdf
theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
theCurve.BitSize = 256
}
// S256 returns a BitCurve which implements secp256k1.
func S256() *BitCurve { func S256() *BitCurve {
initonce.Do(func() {
// See SEC 2 section 2.7.1
// curve parameters taken from:
// http://www.secg.org/collateral/sec2_final.pdf
theCurve = new(BitCurve)
theCurve.P, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16)
theCurve.N, _ = new(big.Int).SetString("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16)
theCurve.B, _ = new(big.Int).SetString("0000000000000000000000000000000000000000000000000000000000000007", 16)
theCurve.Gx, _ = new(big.Int).SetString("79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16)
theCurve.Gy, _ = new(big.Int).SetString("483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16)
theCurve.BitSize = 256
})
return theCurve return theCurve
} }

View file

@ -19,7 +19,7 @@ static secp256k1_context* secp256k1_context_create_sign_verify() {
return secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); return secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
} }
// secp256k1_ecdsa_recover_pubkey recovers the public key of an encoded compact signature. // secp256k1_ext_ecdsa_recover recovers the public key of an encoded compact signature.
// //
// Returns: 1: recovery was successful // Returns: 1: recovery was successful
// 0: recovery was not successful // 0: recovery was not successful
@ -27,7 +27,7 @@ static secp256k1_context* secp256k1_context_create_sign_verify() {
// Out: pubkey_out: the serialized 65-byte public key of the signer (cannot be NULL) // Out: pubkey_out: the serialized 65-byte public key of the signer (cannot be NULL)
// In: sigdata: pointer to a 65-byte signature with the recovery id at the end (cannot be NULL) // In: sigdata: pointer to a 65-byte signature with the recovery id at the end (cannot be NULL)
// msgdata: pointer to a 32-byte message (cannot be NULL) // msgdata: pointer to a 32-byte message (cannot be NULL)
static int secp256k1_ecdsa_recover_pubkey( static int secp256k1_ext_ecdsa_recover(
const secp256k1_context* ctx, const secp256k1_context* ctx,
unsigned char *pubkey_out, unsigned char *pubkey_out,
const unsigned char *sigdata, const unsigned char *sigdata,
@ -46,7 +46,7 @@ static int secp256k1_ecdsa_recover_pubkey(
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED);
} }
// secp256k1_ecdsa_verify_enc verifies an encoded compact signature. // secp256k1_ext_ecdsa_verify verifies an encoded compact signature.
// //
// Returns: 1: signature is valid // Returns: 1: signature is valid
// 0: signature is invalid // 0: signature is invalid
@ -55,7 +55,7 @@ static int secp256k1_ecdsa_recover_pubkey(
// msgdata: pointer to a 32-byte message (cannot be NULL) // msgdata: pointer to a 32-byte message (cannot be NULL)
// pubkeydata: pointer to public key data (cannot be NULL) // pubkeydata: pointer to public key data (cannot be NULL)
// pubkeylen: length of pubkeydata // pubkeylen: length of pubkeydata
static int secp256k1_ecdsa_verify_enc( static int secp256k1_ext_ecdsa_verify(
const secp256k1_context* ctx, const secp256k1_context* ctx,
const unsigned char *sigdata, const unsigned char *sigdata,
const unsigned char *msgdata, const unsigned char *msgdata,
@ -74,28 +74,34 @@ static int secp256k1_ecdsa_verify_enc(
return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey); return secp256k1_ecdsa_verify(ctx, &sig, msgdata, &pubkey);
} }
// secp256k1_decompress_pubkey decompresses a public key. // secp256k1_ext_reencode_pubkey decodes then encodes a public key. It can be used to
// convert between public key formats. The input/output formats are chosen depending on the
// length of the input/output buffers.
// //
// Returns: 1: public key is valid // Returns: 1: conversion successful
// 0: public key is invalid // 0: conversion unsuccessful
// Args: ctx: pointer to a context object (cannot be NULL) // Args: ctx: pointer to a context object (cannot be NULL)
// Out: pubkey_out: the serialized 65-byte public key (cannot be NULL) // Out: out: output buffer that will contain the reencoded key (cannot be NULL)
// In: pubkeydata: pointer to 33 bytes of compressed public key data (cannot be NULL) // In: outlen: length of out (33 for compressed keys, 65 for uncompressed keys)
static int secp256k1_decompress_pubkey( // pubkeydata: the input public key (cannot be NULL)
// pubkeylen: length of pubkeydata
static int secp256k1_ext_reencode_pubkey(
const secp256k1_context* ctx, const secp256k1_context* ctx,
unsigned char *pubkey_out, unsigned char *out,
const unsigned char *pubkeydata size_t outlen,
const unsigned char *pubkeydata,
size_t pubkeylen
) { ) {
secp256k1_pubkey pubkey; secp256k1_pubkey pubkey;
if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, 33)) { if (!secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeydata, pubkeylen)) {
return 0; return 0;
} }
size_t outputlen = 65; unsigned int flag = (outlen == 33) ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
return secp256k1_ec_pubkey_serialize(ctx, pubkey_out, &outputlen, &pubkey, SECP256K1_EC_UNCOMPRESSED); return secp256k1_ec_pubkey_serialize(ctx, out, &outlen, &pubkey, flag);
} }
// secp256k1_pubkey_scalar_mul multiplies a point by a scalar in constant time. // secp256k1_ext_scalar_mul multiplies a point by a scalar in constant time.
// //
// Returns: 1: multiplication was successful // Returns: 1: multiplication was successful
// 0: scalar was invalid (zero or overflow) // 0: scalar was invalid (zero or overflow)
@ -104,7 +110,7 @@ static int secp256k1_decompress_pubkey(
// In: point: pointer to a 64-byte public point, // In: point: pointer to a 64-byte public point,
// encoded as two 256bit big-endian numbers. // encoded as two 256bit big-endian numbers.
// scalar: a 32-byte scalar with which to multiply the point // scalar: a 32-byte scalar with which to multiply the point
int secp256k1_pubkey_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) { int secp256k1_ext_scalar_mul(const secp256k1_context* ctx, unsigned char *point, const unsigned char *scalar) {
int ret = 0; int ret = 0;
int overflow = 0; int overflow = 0;
secp256k1_fe feX, feY; secp256k1_fe feX, feY;

View file

@ -115,7 +115,7 @@ func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
sigdata = (*C.uchar)(unsafe.Pointer(&sig[0])) sigdata = (*C.uchar)(unsafe.Pointer(&sig[0]))
msgdata = (*C.uchar)(unsafe.Pointer(&msg[0])) msgdata = (*C.uchar)(unsafe.Pointer(&msg[0]))
) )
if C.secp256k1_ecdsa_recover_pubkey(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 { if C.secp256k1_ext_ecdsa_recover(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 {
return nil, ErrRecoverFailed return nil, ErrRecoverFailed
} }
return pubkey, nil return pubkey, nil
@ -130,22 +130,42 @@ func VerifySignature(pubkey, msg, signature []byte) bool {
sigdata := (*C.uchar)(unsafe.Pointer(&signature[0])) sigdata := (*C.uchar)(unsafe.Pointer(&signature[0]))
msgdata := (*C.uchar)(unsafe.Pointer(&msg[0])) msgdata := (*C.uchar)(unsafe.Pointer(&msg[0]))
keydata := (*C.uchar)(unsafe.Pointer(&pubkey[0])) keydata := (*C.uchar)(unsafe.Pointer(&pubkey[0]))
return C.secp256k1_ecdsa_verify_enc(context, sigdata, msgdata, keydata, C.size_t(len(pubkey))) != 0 return C.secp256k1_ext_ecdsa_verify(context, sigdata, msgdata, keydata, C.size_t(len(pubkey))) != 0
} }
// DecompressPubkey parses a public key in the 33-byte compressed format. // DecompressPubkey parses a public key in the 33-byte compressed format.
// It returns non-nil coordinates if the public key is valid. // It returns non-nil coordinates if the public key is valid.
func DecompressPubkey(pubkey []byte) (X, Y *big.Int) { func DecompressPubkey(pubkey []byte) (x, y *big.Int) {
if len(pubkey) != 33 { if len(pubkey) != 33 {
return nil, nil return nil, nil
} }
buf := make([]byte, 65) var (
bufdata := (*C.uchar)(unsafe.Pointer(&buf[0])) pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
pubkeydata := (*C.uchar)(unsafe.Pointer(&pubkey[0])) pubkeylen = C.size_t(len(pubkey))
if C.secp256k1_decompress_pubkey(context, bufdata, pubkeydata) == 0 { out = make([]byte, 65)
outdata = (*C.uchar)(unsafe.Pointer(&out[0]))
outlen = C.size_t(len(out))
)
if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 {
return nil, nil return nil, nil
} }
return new(big.Int).SetBytes(buf[1:33]), new(big.Int).SetBytes(buf[33:]) return new(big.Int).SetBytes(out[1:33]), new(big.Int).SetBytes(out[33:])
}
// CompressPubkey encodes a public key to 33-byte compressed format.
func CompressPubkey(x, y *big.Int) []byte {
var (
pubkey = S256().Marshal(x, y)
pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
pubkeylen = C.size_t(len(pubkey))
out = make([]byte, 33)
outdata = (*C.uchar)(unsafe.Pointer(&out[0]))
outlen = C.size_t(len(out))
)
if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 {
panic("libsecp256k1 error")
}
return out
} }
func checkSignature(sig []byte) error { func checkSignature(sig []byte) error {

View file

@ -76,6 +76,11 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil return &ecdsa.PublicKey{X: x, Y: y, Curve: S256()}, nil
} }
// CompressPubkey encodes a public key to the 33-byte compressed format.
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
return secp256k1.CompressPubkey(pubkey.X, pubkey.Y)
}
// S256 returns an instance of the secp256k1 curve. // S256 returns an instance of the secp256k1 curve.
func S256() elliptic.Curve { func S256() elliptic.Curve {
return secp256k1.S256() return secp256k1.S256()

View file

@ -102,6 +102,11 @@ func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) {
return key.ToECDSA(), nil return key.ToECDSA(), nil
} }
// CompressPubkey encodes a public key to the 33-byte compressed format.
func CompressPubkey(pubkey *ecdsa.PublicKey) []byte {
return (*btcec.PublicKey)(pubkey).SerializeCompressed()
}
// S256 returns an instance of the secp256k1 curve. // S256 returns an instance of the secp256k1 curve.
func S256() elliptic.Curve { func S256() elliptic.Curve {
return btcec.S256() return btcec.S256()

View file

@ -18,10 +18,13 @@ package crypto
import ( import (
"bytes" "bytes"
"crypto/ecdsa"
"reflect"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/common/math"
) )
var ( var (
@ -65,6 +68,11 @@ func TestVerifySignature(t *testing.T) {
if VerifySignature(testpubkey, testmsg, sig[:len(sig)-2]) { if VerifySignature(testpubkey, testmsg, sig[:len(sig)-2]) {
t.Errorf("signature valid even though it's incomplete") t.Errorf("signature valid even though it's incomplete")
} }
wrongkey := common.CopyBytes(testpubkey)
wrongkey[10]++
if VerifySignature(wrongkey, testmsg, sig) {
t.Errorf("signature valid with with wrong public key")
}
} }
func TestDecompressPubkey(t *testing.T) { func TestDecompressPubkey(t *testing.T) {
@ -86,6 +94,36 @@ func TestDecompressPubkey(t *testing.T) {
} }
} }
func TestCompressPubkey(t *testing.T) {
key := &ecdsa.PublicKey{
Curve: S256(),
X: math.MustParseBig256("0xe32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a"),
Y: math.MustParseBig256("0x0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652"),
}
compressed := CompressPubkey(key)
if !bytes.Equal(compressed, testpubkeyc) {
t.Errorf("wrong public key result: got %x, want %x", compressed, testpubkeyc)
}
}
func TestPubkeyRandom(t *testing.T) {
const runs = 200
for i := 0; i < runs; i++ {
key, err := GenerateKey()
if err != nil {
t.Fatalf("iteration %d: %v", i, err)
}
pubkey2, err := DecompressPubkey(CompressPubkey(&key.PublicKey))
if err != nil {
t.Fatalf("iteration %d: %v", i, err)
}
if !reflect.DeepEqual(key.PublicKey, *pubkey2) {
t.Fatalf("iteration %d: keys not equal", i)
}
}
}
func BenchmarkEcrecoverSignature(b *testing.B) { func BenchmarkEcrecoverSignature(b *testing.B) {
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
if _, err := Ecrecover(testmsg, testsig); err != nil { if _, err := Ecrecover(testmsg, testsig); err != nil {

View file

@ -17,6 +17,7 @@
package ethapi package ethapi
import ( import (
"bytes"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@ -1003,9 +1004,12 @@ func (s *PublicTransactionPoolAPI) GetRawTransactionByHash(ctx context.Context,
func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) { func (s *PublicTransactionPoolAPI) GetTransactionReceipt(hash common.Hash) (map[string]interface{}, error) {
tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash) tx, blockHash, blockNumber, index := core.GetTransaction(s.b.ChainDb(), hash)
if tx == nil { if tx == nil {
return nil, nil return nil, errors.New("unknown transaction")
} }
receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available receipt, _, _, _ := core.GetReceipt(s.b.ChainDb(), hash) // Old receipts don't have the lookup data available
if receipt == nil {
return nil, errors.New("unknown receipt")
}
var signer types.Signer = types.FrontierSigner{} var signer types.Signer = types.FrontierSigner{}
if tx.Protected() { if tx.Protected() {
@ -1067,8 +1071,11 @@ type SendTxArgs struct {
Gas *hexutil.Big `json:"gas"` Gas *hexutil.Big `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
Value *hexutil.Big `json:"value"` Value *hexutil.Big `json:"value"`
Data hexutil.Bytes `json:"data"`
Nonce *hexutil.Uint64 `json:"nonce"` Nonce *hexutil.Uint64 `json:"nonce"`
// We accept "data" and "input" for backwards-compatibility reasons. "input" is the
// newer name and should be preferred by clients.
Data *hexutil.Bytes `json:"data"`
Input *hexutil.Bytes `json:"input"`
} }
// setDefaults is a helper function that fills in default values for unspecified tx fields. // setDefaults is a helper function that fills in default values for unspecified tx fields.
@ -1093,14 +1100,23 @@ func (args *SendTxArgs) setDefaults(ctx context.Context, b Backend) error {
} }
args.Nonce = (*hexutil.Uint64)(&nonce) args.Nonce = (*hexutil.Uint64)(&nonce)
} }
if args.Data != nil && args.Input != nil && !bytes.Equal(*args.Data, *args.Input) {
return errors.New(`Both "data" and "input" are set and not equal. Please use "input" to pass transaction call data.`)
}
return nil return nil
} }
func (args *SendTxArgs) toTransaction() *types.Transaction { func (args *SendTxArgs) toTransaction() *types.Transaction {
if args.To == nil { var input []byte
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) if args.Data != nil {
input = *args.Data
} else if args.Input != nil {
input = *args.Input
} }
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), args.Data) if args.To == nil {
return types.NewContractCreation(uint64(*args.Nonce), (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input)
}
return types.NewTransaction(uint64(*args.Nonce), *args.To, (*big.Int)(args.Value), (*big.Int)(args.Gas), (*big.Int)(args.GasPrice), input)
} }
// submitTransaction is a helper function that submits tx to txPool and logs a message. // submitTransaction is a helper function that submits tx to txPool and logs a message.

View file

@ -48,7 +48,7 @@ func runTrace(tracer *JavascriptTracer) (interface{}, error) {
contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000) contract := vm.NewContract(account{}, account{}, big.NewInt(0), 10000)
contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0}
_, err := env.Interpreter().Run(0, contract, []byte{}) _, err := env.Interpreter().Run(contract, []byte{})
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -151,7 +151,7 @@ func (t *odrTrie) do(key []byte, fn func() error) error {
} }
r := &TrieRequest{Id: t.id, Key: key} r := &TrieRequest{Id: t.id, Key: key}
if err := t.db.backend.Retrieve(t.db.ctx, r); err != nil { if err := t.db.backend.Retrieve(t.db.ctx, r); err != nil {
return fmt.Errorf("can't fetch trie key %x: %v", key, err) return err
} }
} }
} }

View file

@ -226,14 +226,14 @@ func (db *nodeDB) ensureExpirer() {
// expirer should be started in a go routine, and is responsible for looping ad // expirer should be started in a go routine, and is responsible for looping ad
// infinitum and dropping stale data from the database. // infinitum and dropping stale data from the database.
func (db *nodeDB) expirer() { func (db *nodeDB) expirer() {
tick := time.Tick(nodeDBCleanupCycle) tick := time.NewTicker(nodeDBCleanupCycle)
defer tick.Stop()
for { for {
select { select {
case <-tick: case <-tick.C:
if err := db.expireNodes(); err != nil { if err := db.expireNodes(); err != nil {
log.Error("Failed to expire nodedb items", "err", err) log.Error("Failed to expire nodedb items", "err", err)
} }
case <-db.quit: case <-db.quit:
return return
} }

View file

@ -83,7 +83,7 @@ func (self *Api) Resolve(uri *URI) (storage.Key, error) {
// if the URI is immutable, check if the address is a hash // if the URI is immutable, check if the address is a hash
isHash := hashMatcher.MatchString(uri.Addr) isHash := hashMatcher.MatchString(uri.Addr)
if uri.Immutable() { if uri.Immutable() || uri.DeprecatedImmutable() {
if !isHash { if !isHash {
return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr) return nil, fmt.Errorf("immutable address not a content hash: %q", uri.Addr)
} }

View file

@ -216,7 +216,7 @@ func TestAPIResolve(t *testing.T) {
api := &Api{dns: x.dns} api := &Api{dns: x.dns}
uri := &URI{Addr: x.addr, Scheme: "bzz"} uri := &URI{Addr: x.addr, Scheme: "bzz"}
if x.immutable { if x.immutable {
uri.Scheme = "bzzi" uri.Scheme = "bzz-immutable"
} }
res, err := api.Resolve(uri) res, err := api.Resolve(uri)
if err == nil { if err == nil {

View file

@ -57,7 +57,7 @@ func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) {
if size <= 0 { if size <= 0 {
return "", errors.New("data size must be greater than zero") return "", errors.New("data size must be greater than zero")
} }
req, err := http.NewRequest("POST", c.Gateway+"/bzzr:/", r) req, err := http.NewRequest("POST", c.Gateway+"/bzz-raw:/", r)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -79,7 +79,7 @@ func (c *Client) UploadRaw(r io.Reader, size int64) (string, error) {
// DownloadRaw downloads raw data from swarm // DownloadRaw downloads raw data from swarm
func (c *Client) DownloadRaw(hash string) (io.ReadCloser, error) { func (c *Client) DownloadRaw(hash string) (io.ReadCloser, error) {
uri := c.Gateway + "/bzzr:/" + hash uri := c.Gateway + "/bzz-raw:/" + hash
res, err := http.DefaultClient.Get(uri) res, err := http.DefaultClient.Get(uri)
if err != nil { if err != nil {
return nil, err return nil, err
@ -269,7 +269,7 @@ func (c *Client) DownloadManifest(hash string) (*api.Manifest, error) {
// //
// where entries ending with "/" are common prefixes. // where entries ending with "/" are common prefixes.
func (c *Client) List(hash, prefix string) (*api.ManifestList, error) { func (c *Client) List(hash, prefix string) (*api.ManifestList, error) {
res, err := http.DefaultClient.Get(c.Gateway + "/bzz:/" + hash + "/" + prefix + "?list=true") res, err := http.DefaultClient.Get(c.Gateway + "/bzz-list:/" + hash + "/" + prefix)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -35,8 +35,8 @@ import (
client := httpclient.New() client := httpclient.New()
// for (private) swarm proxy running locally // for (private) swarm proxy running locally
client.RegisterScheme("bzz", &http.RoundTripper{Port: port}) client.RegisterScheme("bzz", &http.RoundTripper{Port: port})
client.RegisterScheme("bzzi", &http.RoundTripper{Port: port}) client.RegisterScheme("bzz-immutable", &http.RoundTripper{Port: port})
client.RegisterScheme("bzzr", &http.RoundTripper{Port: port}) client.RegisterScheme("bzz-raw", &http.RoundTripper{Port: port})
The port you give the Roundtripper is the port the swarm proxy is listening on. The port you give the Roundtripper is the port the swarm proxy is listening on.
If Host is left empty, localhost is assumed. If Host is left empty, localhost is assumed.

View file

@ -86,7 +86,7 @@ type Request struct {
uri *api.URI uri *api.URI
} }
// HandlePostRaw handles a POST request to a raw bzzr:/ URI, stores the request // HandlePostRaw handles a POST request to a raw bzz-raw:/ URI, stores the request
// body in swarm and returns the resulting storage key as a text/plain response // body in swarm and returns the resulting storage key as a text/plain response
func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) { func (s *Server) HandlePostRaw(w http.ResponseWriter, r *Request) {
if r.uri.Path != "" { if r.uri.Path != "" {
@ -291,7 +291,7 @@ func (s *Server) HandleDelete(w http.ResponseWriter, r *Request) {
} }
// HandleGet handles a GET request to // HandleGet handles a GET request to
// - bzzr://<key> and responds with the raw content stored at the // - bzz-raw://<key> and responds with the raw content stored at the
// given storage key // given storage key
// - bzz-hash://<key> and responds with the hash of the content stored // - bzz-hash://<key> and responds with the hash of the content stored
// at the given storage key as a text/plain response // at the given storage key as a text/plain response
@ -434,14 +434,13 @@ func (s *Server) HandleGetFiles(w http.ResponseWriter, r *Request) {
} }
} }
// HandleGetList handles a GET request to bzz:/<manifest>/<path> which has // HandleGetList handles a GET request to bzz-list:/<manifest>/<path> and returns
// the "list" query parameter set to "true" and returns a list of all files // a list of all files contained in <manifest> under <path> grouped into
// contained in <manifest> under <path> grouped into common prefixes using // common prefixes using "/" as a delimiter
// "/" as a delimiter
func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) { func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
// ensure the root path has a trailing slash so that relative URLs work // ensure the root path has a trailing slash so that relative URLs work
if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") { if r.uri.Path == "" && !strings.HasSuffix(r.URL.Path, "/") {
http.Redirect(w, &r.Request, r.URL.Path+"/?list=true", http.StatusMovedPermanently) http.Redirect(w, &r.Request, r.URL.Path+"/", http.StatusMovedPermanently)
return return
} }
@ -463,7 +462,11 @@ func (s *Server) HandleGetList(w http.ResponseWriter, r *Request) {
if strings.Contains(r.Header.Get("Accept"), "text/html") { if strings.Contains(r.Header.Get("Accept"), "text/html") {
w.Header().Set("Content-Type", "text/html") w.Header().Set("Content-Type", "text/html")
err := htmlListTemplate.Execute(w, &htmlListData{ err := htmlListTemplate.Execute(w, &htmlListData{
URI: r.uri, URI: &api.URI{
Scheme: "bzz",
Addr: r.uri.Addr,
Path: r.uri.Path,
},
List: &list, List: &list,
}) })
if err != nil { if err != nil {
@ -599,7 +602,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.Method { switch r.Method {
case "POST": case "POST":
if uri.Raw() { if uri.Raw() || uri.DeprecatedRaw() {
s.HandlePostRaw(w, req) s.HandlePostRaw(w, req)
} else { } else {
s.HandlePostFiles(w, req) s.HandlePostFiles(w, req)
@ -611,7 +614,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
// new manifest leaving the existing one intact, so it isn't // new manifest leaving the existing one intact, so it isn't
// strictly a traditional PUT request which replaces content // strictly a traditional PUT request which replaces content
// at a URI, and POST is more ubiquitous) // at a URI, and POST is more ubiquitous)
if uri.Raw() { if uri.Raw() || uri.DeprecatedRaw() {
ShowError(w, r, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest) ShowError(w, r, fmt.Sprintf("No PUT to %s allowed.", uri), http.StatusBadRequest)
return return
} else { } else {
@ -619,28 +622,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
case "DELETE": case "DELETE":
if uri.Raw() { if uri.Raw() || uri.DeprecatedRaw() {
ShowError(w, r, fmt.Sprintf("No DELETE to %s allowed.", uri), http.StatusBadRequest) ShowError(w, r, fmt.Sprintf("No DELETE to %s allowed.", uri), http.StatusBadRequest)
return return
} }
s.HandleDelete(w, req) s.HandleDelete(w, req)
case "GET": case "GET":
if uri.Raw() || uri.Hash() { if uri.Raw() || uri.Hash() || uri.DeprecatedRaw() {
s.HandleGet(w, req) s.HandleGet(w, req)
return return
} }
if uri.List() {
s.HandleGetList(w, req)
return
}
if r.Header.Get("Accept") == "application/x-tar" { if r.Header.Get("Accept") == "application/x-tar" {
s.HandleGetFiles(w, req) s.HandleGetFiles(w, req)
return return
} }
if r.URL.Query().Get("list") == "true" {
s.HandleGetList(w, req)
return
}
s.HandleGetFile(w, req) s.HandleGetFile(w, req)
default: default:

View file

@ -70,7 +70,7 @@ func TestBzzGetPath(t *testing.T) {
wg.Wait() wg.Wait()
} }
_, err = http.Get(srv.URL + "/bzzr:/" + common.ToHex(key[0])[2:] + "/a") _, err = http.Get(srv.URL + "/bzz-raw:/" + common.ToHex(key[0])[2:] + "/a")
if err != nil { if err != nil {
t.Fatalf("Failed to connect to proxy: %v", err) t.Fatalf("Failed to connect to proxy: %v", err)
} }
@ -79,7 +79,7 @@ func TestBzzGetPath(t *testing.T) {
var resp *http.Response var resp *http.Response
var respbody []byte var respbody []byte
url := srv.URL + "/bzzr:/" url := srv.URL + "/bzz-raw:/"
if k[:] != "" { if k[:] != "" {
url += common.ToHex(key[0])[2:] + "/" + k[1:] + "?content_type=text/plain" url += common.ToHex(key[0])[2:] + "/" + k[1:] + "?content_type=text/plain"
} }
@ -133,10 +133,99 @@ func TestBzzGetPath(t *testing.T) {
} }
} }
for _, c := range []struct {
path string
json string
html string
}{
{
path: "/",
json: `{"common_prefixes":["a/"]}`,
html: "<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/</title>\n</head>\n\n<body>\n <h1>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/</h1>\n <hr>\n <table>\n <thead>\n <tr>\n\t<th>Path</th>\n\t<th>Type</th>\n\t<th>Size</th>\n </tr>\n </thead>\n\n <tbody>\n \n\t<tr>\n\t <td><a href=\"a/\">a/</a></td>\n\t <td>DIR</td>\n\t <td>-</td>\n\t</tr>\n \n\n \n </table>\n <hr>\n</body>\n",
},
{
path: "/a/",
json: `{"common_prefixes":["a/b/"],"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/a","mod_time":"0001-01-01T00:00:00Z"}]}`,
html: "<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/</title>\n</head>\n\n<body>\n <h1>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/</h1>\n <hr>\n <table>\n <thead>\n <tr>\n\t<th>Path</th>\n\t<th>Type</th>\n\t<th>Size</th>\n </tr>\n </thead>\n\n <tbody>\n \n\t<tr>\n\t <td><a href=\"b/\">b/</a></td>\n\t <td>DIR</td>\n\t <td>-</td>\n\t</tr>\n \n\n \n\t<tr>\n\t <td><a href=\"a\">a</a></td>\n\t <td></td>\n\t <td>0</td>\n\t</tr>\n \n </table>\n <hr>\n</body>\n",
},
{
path: "/a/b/",
json: `{"entries":[{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/b","mod_time":"0001-01-01T00:00:00Z"},{"hash":"011b4d03dd8c01f1049143cf9c4c817e4b167f1d1b83e5c6f0f10d89ba1e7bce","path":"a/b/c","mod_time":"0001-01-01T00:00:00Z"}]}`,
html: "<!DOCTYPE html>\n<html>\n<head>\n <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/b/</title>\n</head>\n\n<body>\n <h1>Swarm index of bzz:/262e5c08c03c2789b6daef487dfa14b4d132f5340d781a3ecb1d5122ab65640c/a/b/</h1>\n <hr>\n <table>\n <thead>\n <tr>\n\t<th>Path</th>\n\t<th>Type</th>\n\t<th>Size</th>\n </tr>\n </thead>\n\n <tbody>\n \n\n \n\t<tr>\n\t <td><a href=\"b\">b</a></td>\n\t <td></td>\n\t <td>0</td>\n\t</tr>\n \n\t<tr>\n\t <td><a href=\"c\">c</a></td>\n\t <td></td>\n\t <td>0</td>\n\t</tr>\n \n </table>\n <hr>\n</body>\n",
},
{
path: "/x",
},
{
path: "",
},
} {
k := c.path
url := srv.URL + "/bzz-list:/"
if k[:] != "" {
url += common.ToHex(key[0])[2:] + "/" + k[1:]
}
t.Run("json list "+c.path, func(t *testing.T) {
resp, err := http.Get(url)
if err != nil {
t.Fatalf("HTTP request: %v", err)
}
defer resp.Body.Close()
respbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Read response body: %v", err)
}
body := strings.TrimSpace(string(respbody))
if body != c.json {
isexpectedfailrequest := false
for _, r := range expectedfailrequests {
if k[:] == r {
isexpectedfailrequest = true
}
}
if !isexpectedfailrequest {
t.Errorf("Response list body %q does not match, expected: %v, got %v", k, c.json, body)
}
}
})
t.Run("html list "+c.path, func(t *testing.T) {
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
t.Fatalf("New request: %v", err)
}
req.Header.Set("Accept", "text/html")
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("HTTP request: %v", err)
}
defer resp.Body.Close()
respbody, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("Read response body: %v", err)
}
if string(respbody) != c.html {
isexpectedfailrequest := false
for _, r := range expectedfailrequests {
if k[:] == r {
isexpectedfailrequest = true
}
}
if !isexpectedfailrequest {
t.Errorf("Response list body %q does not match, expected: %q, got %q", k, c.html, string(respbody))
}
}
})
}
nonhashtests := []string{ nonhashtests := []string{
srv.URL + "/bzz:/name", srv.URL + "/bzz:/name",
srv.URL + "/bzzi:/nonhash", srv.URL + "/bzz-immutable:/nonhash",
srv.URL + "/bzzr:/nonhash", srv.URL + "/bzz-raw:/nonhash",
srv.URL + "/bzz-list:/nonhash",
srv.URL + "/bzz-hash:/nonhash", srv.URL + "/bzz-hash:/nonhash",
} }
@ -145,6 +234,7 @@ func TestBzzGetPath(t *testing.T) {
"error resolving nonhash: immutable address not a content hash: &#34;nonhash&#34;", "error resolving nonhash: immutable address not a content hash: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;", "error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;", "error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
"error resolving nonhash: no DNS to resolve name: &#34;nonhash&#34;",
} }
for i, url := range nonhashtests { for i, url := range nonhashtests {

View file

@ -52,7 +52,7 @@ var htmlListTemplate = template.Must(template.New("html-list").Funcs(template.Fu
<tbody> <tbody>
{{ range .List.CommonPrefixes }} {{ range .List.CommonPrefixes }}
<tr> <tr>
<td><a href="{{ basename . }}/?list=true">{{ basename . }}/</a></td> <td><a href="{{ basename . }}/">{{ basename . }}/</a></td>
<td>DIR</td> <td>DIR</td>
<td>-</td> <td>-</td>
</tr> </tr>

View file

@ -26,7 +26,13 @@ import (
type URI struct { type URI struct {
// Scheme has one of the following values: // Scheme has one of the following values:
// //
// * bzz - an entry in a swarm manifest // * bzz - an entry in a swarm manifest
// * bzz-raw - raw swarm content
// * bzz-immutable - immutable URI of an entry in a swarm manifest
// (address is not resolved)
// * bzz-list - list of all files contained in a swarm manifest
//
// Deprecated Schemes:
// * bzzr - raw swarm content // * bzzr - raw swarm content
// * bzzi - immutable URI of an entry in a swarm manifest // * bzzi - immutable URI of an entry in a swarm manifest
// (address is not resolved) // (address is not resolved)
@ -52,7 +58,9 @@ type URI struct {
// * <scheme>://<addr> // * <scheme>://<addr>
// * <scheme>://<addr>/<path> // * <scheme>://<addr>/<path>
// //
// with scheme one of bzz, bzzr, bzzi or bzz-hash
// with scheme one of bzz, bzz-raw, bzz-immutable, bzz-list or bzz-hash
// or deprecated ones bzzr and bzzi
func Parse(rawuri string) (*URI, error) { func Parse(rawuri string) (*URI, error) {
u, err := url.Parse(rawuri) u, err := url.Parse(rawuri)
if err != nil { if err != nil {
@ -62,7 +70,7 @@ func Parse(rawuri string) (*URI, error) {
// check the scheme is valid // check the scheme is valid
switch uri.Scheme { switch uri.Scheme {
case "bzz", "bzzi", "bzzr", "bzz-hash": case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzzr", "bzzi":
default: default:
return nil, fmt.Errorf("unknown scheme %q", u.Scheme) return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
} }
@ -86,10 +94,22 @@ func Parse(rawuri string) (*URI, error) {
} }
func (u *URI) Raw() bool { func (u *URI) Raw() bool {
return u.Scheme == "bzzr" return u.Scheme == "bzz-raw"
} }
func (u *URI) Immutable() bool { func (u *URI) Immutable() bool {
return u.Scheme == "bzz-immutable"
}
func (u *URI) List() bool {
return u.Scheme == "bzz-list"
}
func (u *URI) DeprecatedRaw() bool {
return u.Scheme == "bzzr"
}
func (u *URI) DeprecatedImmutable() bool {
return u.Scheme == "bzzi" return u.Scheme == "bzzi"
} }

View file

@ -23,12 +23,15 @@ import (
func TestParseURI(t *testing.T) { func TestParseURI(t *testing.T) {
type test struct { type test struct {
uri string uri string
expectURI *URI expectURI *URI
expectErr bool expectErr bool
expectRaw bool expectRaw bool
expectImmutable bool expectImmutable bool
expectHash bool expectList bool
expectHash bool
expectDeprecatedRaw bool
expectDeprecatedImmutable bool
} }
tests := []test{ tests := []test{
{ {
@ -48,13 +51,13 @@ func TestParseURI(t *testing.T) {
expectURI: &URI{Scheme: "bzz"}, expectURI: &URI{Scheme: "bzz"},
}, },
{ {
uri: "bzzi:", uri: "bzz-immutable:",
expectURI: &URI{Scheme: "bzzi"}, expectURI: &URI{Scheme: "bzz-immutable"},
expectImmutable: true, expectImmutable: true,
}, },
{ {
uri: "bzzr:", uri: "bzz-raw:",
expectURI: &URI{Scheme: "bzzr"}, expectURI: &URI{Scheme: "bzz-raw"},
expectRaw: true, expectRaw: true,
}, },
{ {
@ -70,18 +73,18 @@ func TestParseURI(t *testing.T) {
expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"}, expectURI: &URI{Scheme: "bzz", Addr: "abc123", Path: "path/to/entry"},
}, },
{ {
uri: "bzzr:/", uri: "bzz-raw:/",
expectURI: &URI{Scheme: "bzzr"}, expectURI: &URI{Scheme: "bzz-raw"},
expectRaw: true, expectRaw: true,
}, },
{ {
uri: "bzzr:/abc123", uri: "bzz-raw:/abc123",
expectURI: &URI{Scheme: "bzzr", Addr: "abc123"}, expectURI: &URI{Scheme: "bzz-raw", Addr: "abc123"},
expectRaw: true, expectRaw: true,
}, },
{ {
uri: "bzzr:/abc123/path/to/entry", uri: "bzz-raw:/abc123/path/to/entry",
expectURI: &URI{Scheme: "bzzr", Addr: "abc123", Path: "path/to/entry"}, expectURI: &URI{Scheme: "bzz-raw", Addr: "abc123", Path: "path/to/entry"},
expectRaw: true, expectRaw: true,
}, },
{ {
@ -106,6 +109,36 @@ func TestParseURI(t *testing.T) {
expectURI: &URI{Scheme: "bzz-hash"}, expectURI: &URI{Scheme: "bzz-hash"},
expectHash: true, expectHash: true,
}, },
{
uri: "bzz-list:",
expectURI: &URI{Scheme: "bzz-list"},
expectList: true,
},
{
uri: "bzz-list:/",
expectURI: &URI{Scheme: "bzz-list"},
expectList: true,
},
{
uri: "bzzr:",
expectURI: &URI{Scheme: "bzzr"},
expectDeprecatedRaw: true,
},
{
uri: "bzzr:/",
expectURI: &URI{Scheme: "bzzr"},
expectDeprecatedRaw: true,
},
{
uri: "bzzi:",
expectURI: &URI{Scheme: "bzzi"},
expectDeprecatedImmutable: true,
},
{
uri: "bzzi:/",
expectURI: &URI{Scheme: "bzzi"},
expectDeprecatedImmutable: true,
},
} }
for _, x := range tests { for _, x := range tests {
actual, err := Parse(x.uri) actual, err := Parse(x.uri)
@ -127,8 +160,17 @@ func TestParseURI(t *testing.T) {
if actual.Immutable() != x.expectImmutable { if actual.Immutable() != x.expectImmutable {
t.Fatalf("expected %s immutable to be %t, got %t", x.uri, x.expectImmutable, actual.Immutable()) t.Fatalf("expected %s immutable to be %t, got %t", x.uri, x.expectImmutable, actual.Immutable())
} }
if actual.List() != x.expectList {
t.Fatalf("expected %s list to be %t, got %t", x.uri, x.expectList, actual.List())
}
if actual.Hash() != x.expectHash { if actual.Hash() != x.expectHash {
t.Fatalf("expected %s hash to be %t, got %t", x.uri, x.expectHash, actual.Hash()) t.Fatalf("expected %s hash to be %t, got %t", x.uri, x.expectHash, actual.Hash())
} }
if actual.DeprecatedRaw() != x.expectDeprecatedRaw {
t.Fatalf("expected %s deprecated raw to be %t, got %t", x.uri, x.expectDeprecatedRaw, actual.DeprecatedRaw())
}
if actual.DeprecatedImmutable() != x.expectDeprecatedImmutable {
t.Fatalf("expected %s deprecated immutable to be %t, got %t", x.uri, x.expectDeprecatedImmutable, actual.DeprecatedImmutable())
}
} }
} }

View file

@ -46,7 +46,7 @@ main() {
} }
do_random_upload() { do_random_upload() {
curl -fsSL -X POST --data-binary "$(random_data)" "http://${addr}/bzzr:/" curl -fsSL -X POST --data-binary "$(random_data)" "http://${addr}/bzz-raw:/"
} }
random_data() { random_data() {